JBoss.org Community Documentation
Customers: Enterprise customers deploying JBoss technologies in mission-critical applications with professional services support from JBoss include Aviva Canada, Continental Airlines, La Quinta, NLG, MCI, Nielsen Media Research and Travelocity. For a current list of customer success stories, please visit the Customers section of our website.
Partners: JBoss works with software and hardware vendors, systems integrators and OEMs to deliver implementation services, frontline support, and certification for products embedded with JBoss technologies. For more information on the JBoss Certified Partner Program, please visit the Partners section of our website.
Professional Open Source(tm) from JBoss Inc. offers you:
Standards-based and stable Java Middleware technology
No cost open source product licenses
Backed by a professional and expert support staff
Comprehensive services including Professional Support, Training, and Consulting
A very large and active community of developers
An extensive worldwide network of authorized and certified partners
Benefits of Professional Open Source from JBoss Inc.:
Lowest possible total cost of ownership
Reliable and safe technology
Support, accountability, and trust from a stable company
Expedited problem resolution compared to commercial software vendors
The basic idea behind open source is very simple: When programmers can read, redistribute, and modify the source code for a piece of software, the software evolves. People improve it, people adapt it, people fix bugs. And this can happen at a speed that, if one is used to the slow pace of conventional software development, seems astonishing. Open Source is an often-misunderstood term relating to free software. The Open Source Initiative (OSI) web site provides a number of resources that define the various aspects of Open Source including an Open Source Definition at: http://www.opensource.org/docs/definition.html. The following quote from the OSI home page summarizes the key aspects as they relate to JBoss nicely:
|
We in the open source community have learned that this rapid evolutionary process produces better software than the traditional closed model, in which only very few programmers can see the source and everybody else must blindly use an opaque block of bits. Open Source Initiative exists to make this case to the commercial world. Open source software is an idea whose time has finally come. For twenty years it has been building momentum in the technical cultures that built the Internet and the World Wide Web. Now it's breaking out into the commercial world, and that's changing all the rules. Are you ready? |
||
| --The Open Source Initiative | ||
If you find a typographical error in the Administration and Configuration Guide, or if you have thought of a way to make this manual better, we would love to hear from you! Please submit a report in JIRA: http://jira.jboss.com against the project JBoss Application Server and component Documentation.
If you have a suggestion for improving the documentation, try to be as specific as possible when describing it. If you have found an error, please include the section number and some of the surrounding text so we can find it easily.
Be sure to give us your name so you can receive full credit.
This content is taken from svn.jboss.org/repos/jbossas/projects/docs/trunk and has yet to be branched.
To access the content directly and make changes yourself:
svn co https://svn.jboss.org/repos/jbossas/projects/docs/trunk/AS_5/Administration_And_Configuration_Guide/ --username yourname
The directory structure includes other languages the book will be translated in. For English please edit the files under en-US .
To identify the filename you wish to edit, please check the chapter title which will match the file's name. The files are written in Docbook xml. After saving your changes please validate the files you've edited for error's before committing your changes.
JBoss Application Server 5 is built on top of the new JBoss Microcontainer. The JBoss Microcontainer is a lightweight container that supports direct deployment, configuration and lifecycle of plain old Java objects (POJOs). The JBoss Microcontainer project is standalone and replaces the JBoss JMX Microkernel used in the 3.x and 4.x JBoss Application Servers. Project goals include:
Make the JBoss Microcontainer available as a standalone project.
Embrace JBoss' POJO middleware strategy.
Enable JBoss services to be easily deployed in the other containers.
Allow the features to be used in more restrictive environments (e.g. Applets, J2ME, etc.).
Provide POJO configuration management, support for dependencies, and support for clustering.
The JBoss Microcontainer integrates nicely with the JBoss Aspect Oriented Programming framework (JBoss AOP). JBoss AOP is discussed in Chapter 7, JBOSS AOP Support for JMX in JBoss AS 5 remains strong and MBean services written against the old Microkernel are expected to work.
JBoss AS5 is designed around the advanced concept of a Virtual Deployment Framework (VDF). The JBoss5 Virtual Deployment Framework (VDF) takes the aspect oriented design of many of the earlier JBoss containers and applies it to the deployment layer. It is also based on the POJO microntainer rather than JMX as in previous releases. More information about the Virtual Deployment Framework (VDF) can be found in Chapter 6, JBoss5 Virtual Deployment Framework .
A sample Java EE 5 application that can be run on top of JBoss 5.0.0.Beta4 and above which demonstrates many interesting technologies is the Seam Booking Application available on http://seam.demo.jboss.com/home.seam. This application makes use of the following technologies running on JBoss AS5:
EJB3
Stateful Session Beans
Stateless Session Beans
JPA (w/ Hibernate validation)
JSF
Facelets
Ajax4JSF
Seam
Many key features of JBoss AS5 are provided by integrating other standalone JBoss projects which include: -
JBoss EJB3 included with JBoss 5 provides the implementation of the latest revision of the Enterprise Java Beans (EJB) specification. EJB 3.0 is a deep overhaul and simplification of the EJB specification. EJB 3.0's goals are to simplify development, facilitate a test driven approach, and focus more on writing plain old java objects (POJOs) rather than coding against complex EJB APIs.
JBoss Messaging is a high performance JMS provider in the JBoss Enterprise Middleware Stack (JEMS), included with JBoss 5 as the default messaging provider. It is also the backbone of the JBoss ESB infrastructure. JBoss Messaging is a complete rewrite of JBossMQ, which is the default JMS provider for the JBoss AS 4.x series.
JBossCache 2.0 that comes in two flavors. A traditional tree-structured node-based cache and a PojoCache, an in-memory, transactional, and replicated cache system that allows users to operate on simple POJOs transparently without active user management of either replication or persistency aspects.
JBossWS 2 is the web services stack for JBoss 5 providing Java EE compatible web services, JAXWS-2.0.
JBoss Transactions is the default transaction manager for JBoss 5. JBoss Transactions is founded on industry proven technology and 18 year history as a leader in distributed transactions, and is one of the most interoperable implementations available.
JBoss Web is the Web container in JBoss 5, an implementation based on Apache Tomcat that includes the Apache Portable Runtime (APR) and Tomcat native technologies to achieve scalability and performance characteristics that match and exceed the Apache Http server.
JBoss AS5 includes numerous features and bug fixes, many of them carried over upstream from the JBoss AS4.x codebase. See the Detailed Release Notes section for the full details.
99% of web apps involve a database
mission critical web applications likely to be clustered.
Simple web applications with JSPs/Servlets upgrade to jboss As with tomcat embedded.
Cross application middleware (JMS, Corba, JMX etc).
JBoss Enterprise Application Platform is a rigorously tested, stable, supported platform for developing and deploying mission critical Java applications and services. It integrates code from the JBoss.org Application Server/Clustering project, JBoss Hibernate Framework, JBoss Seam Framework into a single distribution with a single patch and update stream, multi-year maintenance policy. JBoss EAP is certified on 17 operating systems, 5 Database Management systems and JVM combinations. It also integrates with JBoss Developer Studio and the JBoss Operations Network.
Key benefits of using JBoss:
significant CPU deployments,
commitment to web apps, and experience with open source
The need to reduce operational costs. You can reduce enterprise middleware costs by upto 70%. With zero licence fees you can refocus savings on business differentiation. JBoss Middleware is Enterprise-class technology with significantly lower Total Cost of ownership (TCO).
The need/desire to shed vendor lock in and high maintenance/support fees. Jboss Mitigates risks and helps customers avoid vendor lock in. You can therefore start new projects without any cost prohibition. You can use the Application Server with other middleware such as Hibernate and Websphere. With Red Hat open source Assurance program the code is always there and not dependent on a single vendor.
unplanned growth of systems leads to unplanned maintenance and licence cost increases.
System consolidation – mergers and acquisitions.
You can consistently meet service level agreements (SLA's) with as little change as possible by back porting patches to previous versions. With 24x7x365 support with 1 hour SLA you are guaranteed support when you need it. Please visit http://jboss.com/services/profsupport for more details. Performance tuning and certification services are also available to our customers. Automated patch and upgrade management on JBoss Enterprise middleware increases reliability of resources with minimal downtime if any.
Multi channel integration needs leading to Service Oriented Architecture (SOA).
More information about JBoss Enterprise Application Platform and Enterprise middleware can be obtained on http://www.jboss.com/products/index and http://www.redhat.com/promo/migration/
The following are current compatibility issues for JBoss AS5:
JBossAS 5 runs under Java 5 but there is an ongoing task to make it run safely under Java 6, too http://jira.jboss.org/jira/browse/JBAS-5031. If using a Sun Java 6 runtime, you may want to set -Dsun.lang.ClassLoader.allowArraySyntax=true, as described in http://jira.jboss.org/jira/browse/JBAS-4491.
If using proprietary JBoss/EJB3 annotations, those have moved into the org.jboss.ejb3.annotation package, http://jira.jboss.org/jira/browse/EJBTHREE-1099. Those are now included in a new artifact, jboss-ejb3-ext-api.jar
Work on EJB3 Extended Persistence Context support is not completed, http://jira.jboss.org/jira/browse/EJBTHREE-1026.
Interoperating with previous JBoss EJB3 implementations may present problems due to serialVersionUIDs issues, http://jira.jboss.org/jira/browse/EJBTHREE-1118.
EJB 2.1 View requirements
Home extending EJBLocalHome? or EJBHome must be defined
Remote or Local interface must either be defined via @Local/@Remote or via return type of "create<METHOD>" methods of the Home
EJB 2.1 Remote/Local interfaces must extend EJBObject/EJBLocalObject
@Local/@Remote may be used to define either EJB 3.0 View Business Interface, or EJB 2.1 View Remote/Local interface
Use of JBoss Cache 2.x. JBC 2.x has a significantly different API from the 1.x releases used in JBoss AS 4.x and 3.2.x.
The directory structure of JBoss 5 resembles that of the 4.x series with some notable differences:
-<JBOSS_HOME>/ - the path to your JBoss AS installation. + bin/ - contains start scripts and run.jar + client/ - client jars + docs/ - docs, schemas/dtds, examples + lib/ - core bootstrap jars, different with the introduction of the microcontainer and breakup of jboss-common. + server/ - contains the same server configuration directories. + default/ configuration + conf/ - contains server configuration files used when starting the server. changes in here are detected on restarting your server. # bootstrap-beans.xml - new mc kernel bootstrap configuration # jax-ws-catalog.xml - oasis catalog driven schema/dtd namespace configuration # jbossjta-properties.xml - new JBossTS properties # jboss-service.xml - legacy static mbeans for compatibility # jndi.properties - the same jndi props # log4j.xml - the same log4j config # login-config.xml - the same jaas login config # props/ - the same default jaas login properties files # standardjaws.xml - obsolete cmp config # standardjbosscmp-jdbc.xml - the same cmp2 config # standardjboss.xml - the same ejb2 config # xmdesc/ - legacy xmbean descriptors + data/ - contains hypersonic local database, transactions, xmbean configuration files. + deploy/ - this is where services and your java applications are deployed. You can deploy an application on the JBoss application server by simply copying the application's (WAR, EAR or JAR files) into this directory. + deployers/ - new vdf deployers # bsh-deployer - beanshell deployer # ejb3.deployer - ejb3 deployers # jboss-aop-jboss5.deployer - aspect deployer # jboss-jca.deployer - JCA deployers # jbossweb.deployer - war deployers # jbossws.deployer - web services deployers # ear-deployer-beans.xml - ear deployers # ejb-deployer-beans.xml - ejb2.x deployers # metadata-beans.xml - metadata handlers # security-deployer-beans.xml - security deployers # profileservice-beans.xml.bak - an example of the repository based profile service + lib/ - the JBoss AS static library files shared by the services and applications in the respective configuration.
Deploying applications on JBoss AS is very easy. You just need to copy the application into the JBOSS_HOME/server/default/deploy directory. You can replace default with different server profiles such as all or minimal. We will cover those later in this chapter. JBoss AS constantly scans the deploy directory to pick up new applications or any changes to existing applications. So, you can "hot deploy" application on the fly while JBoss AS is still running.
You can deploy several different types of enterprise applications in JBoss AS:
JBoss Application Server 5.0 uses the microcontainer to integrate enterprise services together with a Servlet/JSP container, EJB container, deployers and management utilities in order to provide a standard Java EE environment. If you need additional services then you can simply deploy these on top of Java EE to provide the functionality you need. Likewise you are free to remove any services that you don't need simply by changing the configuration. You can even use the microcontainer to do this in other environments such as Tomcat and GlassFish since you can plug in different classloading models during the service deployment phase.
Since JBoss Microcontainer is very lightweight and deals with POJOs it can also be used to deploy services into a Java ME runtime environment. This opens up new possibilities for mobile applications that can now take advantage of enterprise services without requiring a full JEE application server.
In common with other lightweight containers JBoss Microcontainer uses dependency injection to wire individual POJOs together to create services. Configuration is performed using either annotations or XML depending on where the information is best located. Finally unit testing is made extremely simple thanks to a helper class that extends JUnit to setup the test environment, allowing you to access POJOs and services from your test methods using just a few lines of code.
aop-mc-int handles integration between the JBossAOP and Microcontainer projects
The managed module defines the base objects defining the management view of a component.
The metatype metatype module defines the base types found in the management view of a component.
osgi-int contains the integration classes that adapt the OSGi model onto the Microcontainer.
spring-int contains the integration classes that adapt the spring model onto the Microcontainer.
<deployment xmlns="urn:jboss:bean-deployer:2.0"> <!-- All beans use the bootstrap classloader --> <classloader><inject bean="BootstrapClassLoader"/></classloader> <!-- TODO Should split this file up and use the new classloader --> <bean name="BootstrapClassLoader" class="org.jboss.system.NoAnnotationURLClassLoader"> <classloader><null/></classloader> <constructor factoryClass="org.jboss.system.NoAnnotationURLClassLoader" factoryMethod="createClassLoader"> <parameter> ..... ...... <bean name="ProfileServiceBootstrap" class="org.jboss.system.server.profileservice.ProfileServiceBootstrap"> <property name="kernel"><inject bean="jboss.kernel:service=Kernel"/></property> </bean> <!-- The legacy JMX kernel --> <bean name="JMXKernel" class="org.jboss.system.server.jmx.JMXKernel"> <property name="kernel"><inject bean="jboss.kernel:service=Kernel"/></property> <property name="serverImpl"><inject bean="JBossServer"/></property> <property name="oldClassLoader">false</property> </bean> ....(content truncated) ...... <!-- The ManagedDeploymentCreator implementation --> <bean name="ManagedDeploymentCreator" class="org.jboss.deployers.plugins.managed.DefaultManagedDeploymentCreator" /> <!-- The holder for deployers that determine structure --> <bean name="StructuralDeployers" class="org.jboss.deployers.vfs.plugins.structure.VFSStructuralDeployersImpl"> <property name="structureBuilder"> <!-- The consolidator of the structure information --> <bean name="StructureBuilder" class="org.jboss.deployers.vfs.plugins.structure.VFSStructureBuilder"/> </property> <!-- Accept any implementor of structure deployer --> <incallback method="addDeployer"/> <uncallback method="removeDeployer"/> </bean> ...(content truncated) ...
AspectManager? : the AOP aspects
ServiceClassLoaderDeployer? : this bean manages the class loading aspect of deployment.
AspectDeployer? : handles aop descriptor deployments.
BeanMetaDataDeployer? : creates the kernel beans from the deployment BeanMetaData.
ServiceDeployer? : creates the mbean services from deployment ServiceMetaData instances.
Web services are a key contributing factor in the ways Web commerce is conducted today. Web services enable application/programs to communicate by sending small and large chunks of data to each other.
A web service is essentially a software application that supports interaction of applications over a computer network or the world wide web. Web services usually interact via XML documents that map to an object, computer program, business process or database. To communicate, an application sends a message in XML document format to a web service which sends this message to the respective programs. Responses may be received based on requirements and the web service receives and sends them in XML document format to the required program or applications. Web services can be used in many ways examples include supply chain information management and business integration among a multitude of other applications.
JBossWS is a web service framework developed as part of the JBoss Application Server. It implements the JAX-WS specification that defines a programming model and run-time architecture for implementing web services in Java, targeted at the Java Platform, Enterprise Edition 5 (Java EE 5).
JBossWS integrates with most current JBoss Application Server releases as well as earlier ones, that did implement the J2EE 1.4 specifications. Even though JAX-RPC, the web service specification for J2EE 1.4, is still supported JBossWS does put a clear focus on JAX-WS.
/** * Payload bean that will use SwaRef encoding */ @XmlRootElement public class DocumentPayload { private DataHandler data; public DocumentPayload() { } public DocumentPayload(DataHandler data) { this.data = data; } @XmlElement @XmlAttachmentRef public DataHandler getData() { return data; } public void setData(DataHandler data) { this.data = data; } } With document wrapped endpoints you may even specify the @XmlAttachmentRef annotation on the service endpoint interface: @WebService public interface DocWrappedEndpoint { @WebMethod DocumentPayload beanAnnotation(DocumentPayload dhw, String test); @WebMethod @XmlAttachmentRef DataHandler parameterAnnotation(@XmlAttachmentRef DataHandler data, String test); }
The message would then refer to the attachment part by CID:
<env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'> <env:Header/> <env:Body> <ns2:parameterAnnotation xmlns:ns2='http://swaref.samples.jaxws.ws.test.jboss.org/'> <arg0>cid:0-1180017772935-32455963@ws.jboss.org</arg0> <arg1>Wrapped test</arg1> </ns2:parameterAnnotation> </env:Body> </env:Envelope>
SOAP Message Transmission Optimization Mechanism ((MTOM) http://www.w3.org/TR/soap12-mtom/)
XML-binary Optimized Packaging (XOP) (http://www.w3.org/TR/xop10/)
|
image/jpeg |
java.awt.Image |
|
text/xml |
javax.xml.transform.Source |
|
application/xml |
javax.xml.transform.Source |
|
application/octet-stream |
javax.activation.DataHandler |
Table 5.1. Supported MTOM parameter types
package org.jboss.test.ws.jaxws.samples.xop.doclit; import javax.ejb.Remote; import javax.jws.WebService; import javax.jws.soap.SOAPBinding; import javax.xml.ws.BindingType; @Remote @WebService(targetNamespace = "http://org.jboss.ws/xop/doclit") @SOAPBinding(style = SOAPBinding.Style.DOCUMENT, parameterStyle = SOAPBinding.ParameterStyle.BARE) @BindingType(value="http://schemas.xmlsoap.org/wsdl/soap/http?mtom=true") (1) public interface MTOMEndpoint { [...] }
[...] Service service = Service.create(wsdlURL, serviceName); port = service.getPort(MTOMEndpoint.class); // enable MTOM binding = (SOAPBinding)((BindingProvider)port).getBinding(); binding.setMTOMEnabled(true);
<binding name='EndpointInterfaceBinding' type='tns:EndpointInterface'> <soap:binding style='document' transport='http://schemas.xmlsoap.org/soap/http'/> <operation name='concat'> <soap:operation soapAction=''/> <input> <soap:body use='literal'/> </input> <output> <soap:body use='literal'/> </output> </operation> </binding>
<complexType name='concatType'> <sequence> <element name='String_1' nillable='true' type='string'/> <element name='long_1' type='long'/> </sequence> </complexType> <element name='concat' type='tns:concatType'/> Therefore, message parts must refer to an element from the schema. <message name='EndpointInterface_concat'> <part name='parameters' element='tns:concat'/> </message> The following message definition is invalid. <message name='EndpointInterface_concat'> <part name='parameters' type='tns:concatType'/> </message>
@WebService @SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE) public class DocBareServiceImpl { @WebMethod public SubmitBareResponse submitPO(SubmitBareRequest poRequest) { ... } }
@XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "SubmitBareRequest", namespace="http://soapbinding.samples.jaxws.ws.test.jboss.org/", propOrder = { "product" }) @XmlRootElement(namespace="http://soapbinding.samples.jaxws.ws.test.jboss.org/", name = "SubmitPO") public class SubmitBareRequest { @XmlElement(namespace="http://soapbinding.samples.jaxws.ws.test.jboss.org/", required = true) private String product; ... }
@WebService public class DocWrappedServiceImpl { @WebMethod @RequestWrapper (className="org.somepackage.SubmitPO") @ResponseWrapper (className="org.somepackage.SubmitPOResponse") public String submitPO(String product, int quantity) { ... } }
The port type operation name defines the endpoint method name
Message parts are endpoint method parameters
RPC is defined by the style attribute on the SOAP binding.
<binding name='EndpointInterfaceBinding' type='tns:EndpointInterface'> <soap:binding style='rpc' transport='http://schemas.xmlsoap.org/soap/http'/> <operation name='echo'> <soap:operation soapAction=''/> <input> <soap:body namespace='http://org.jboss.ws/samples/jsr181pojo' use='literal'/> </input> <output> <soap:body namespace='http://org.jboss.ws/samples/jsr181pojo' use='literal'/> </output> </operation> </binding>
With rpc style web services the portType names the operation (i.e. the java method on the endpoint)
<portType name='EndpointInterface'> <operation name='echo' parameterOrder='String_1'> <input message='tns:EndpointInterface_echo'/> <output message='tns:EndpointInterface_echoResponse'/> </operation> </portType>
Operation parameters are defined by individual message parts.
<message name='EndpointInterface_echo'> <part name='String_1' type='xsd:string'/> </message> <message name='EndpointInterface_echoResponse'> <part name='result' type='xsd:string'/> </message>
Note, there is no complex type in XML schema that could validate the entire SOAP message payload.
@WebService @SOAPBinding(style = SOAPBinding.Style.RPC) public class JSEBean01 { @WebMethod @WebResult(name="result") public String echo(@WebParam(name="String_1") String input) { ... } }
SOAP encodeding style is defined by the infamous chapter 5 of the SOAP-1.1 specification. It has inherent interoperability issues that cannot be fixed. The Basic Profile-1.0 prohibits this encoding style in 4.1.7 SOAP encodingStyle Attribute. JBossWS has basic support for rpc/encoded that is provided as is for simple interop scenarios with SOAP stacks that do not support literal encoding. Specifically, JBossWS does not support:-
element references
soap arrays as bean properties
@WebService @SOAPBinding(style = SOAPBinding.Style.RPC) public class JSEBean01 { @WebMethod public String echo(String input) { ... } }
A JAX-WS java service endpoint (JSE) is deployed as a web application.
<web-app ...> <servlet> <servlet-name>TestService</servlet-name> <servlet-class>org.jboss.test.ws.jaxws.samples.jsr181pojo.JSEBean01</servlet-class> </servlet> <servlet-mapping> <servlet-name>TestService</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app>
A JSR-181 java service endpoint (JSE) is packaged as a web application in a *.war file.
<war warfile="${build.dir}/libs/jbossws-samples-jsr181pojo.war" webxml="${build.resources.dir}/samples/jsr181pojo/WEB-INF/web.xml"> <classes dir="${build.dir}/classes"> <include name="org/jboss/test/ws/samples/jsr181pojo/JSEBean01.class"/> </classes> </war>
Note that only the endpoint implementation bean and web.xml are required.
http://yourhost:8080/jbossws/services
a Note, it is also possible to generate the abstract contract off line using jbossw tools. For details of that please see #Top Down (Java to WSDL)
The JAX-WS programming model support the same set of annotations on EJB3 stateless session beans as on # Plain old Java Object (POJO) endpoints. EJB-2.1 endpoints are supported using the JAX-RPC progamming model.
@Stateless
@Remote(EJB3RemoteInterface.class)
@RemoteBinding(jndiBinding = "/ejb3/EJB3EndpointInterface")
@WebService
@SOAPBinding(style = SOAPBinding.Style.RPC)
public class EJB3Bean01 implements EJB3RemoteInterface
{
@WebMethod
public String echo(String input)
{
...
}
}
Above you see an EJB-3.0 stateless session bean that exposes one method both on the remote interface and on and as an endpoint operation.
Packaging the endpoint
A JSR-181 EJB service endpoint is packaged as an ordinary ejb deployment.
<jar jarfile="${build.dir}/libs/jbossws-samples-jsr181ejb.jar">
<fileset dir="${build.dir}/classes">
<include name="org/jboss/test/ws/samples/jsr181ejb/EJB3Bean01.class"/>
<include name="org/jboss/test/ws/samples/jsr181ejb/EJB3RemoteInterface.class"/>
</fileset>
</jar>
Accessing the generated WSDL
A successfully deployed service endpoint will show up in the service endpoint manager. This is also where you find the links to the generated wsdl.
http://yourhost:8080/jbossws/services
Note, it is also possible to generate the abstract contract off line using jbossw tools. For details of that please see #Top Down (Java to WSDL)
@WebServiceProvider @ServiceMode(value = Service.Mode.PAYLOAD) public class ProviderBeanPayload implements Provider<Source> { public Source invoke(Source req) { // Access the entire request PAYLOAD and return the response PAYLOAD } }
@WebService public class EndpointJSE { @Resource WebServiceContext wsCtx; @WebMethod public String testGetMessageContext() { SOAPMessageContext jaxwsContext = (SOAPMessageContext)wsCtx.getMessageContext(); return jaxwsContext != null ? "pass" : "fail"; } .. @WebMethod public String testGetUserPrincipal() { Principal principal = wsCtx.getUserPrincipal(); return principal.getName(); } @WebMethod public boolean testIsUserInRole(String role) { return wsCtx.isUserInRole(role); } }
The following code snippet shows the generated constructors from the generated class:
// Generated Service Class @WebServiceClient(name="StockQuoteService", targetNamespace="http://example.com/stocks", wsdlLocation="http://example.com/stocks.wsdl") public class StockQuoteService extends javax.xml.ws.Service { public StockQuoteService() { super(new URL("http://example.com/stocks.wsdl"), new QName("http://example.com/stocks", "StockQuoteService")); } public StockQuoteService(String wsdlLocation, QName serviceName) { super(wsdlLocation, serviceName); } ... }
Section #Dynamic Proxy explains how to obtain a port from the service and how to invoke an operation on the port. If you need to work with the XML payload directly or with the XML representation of the entire SOAP message, have a look at #Dispatch.
Dynamic case
In the dynamic case, when nothing is generated, a web service client uses Service.create to create Service instances, the following code illustrates this process.
URL wsdlLocation = new URL("http://example.org/my.wsdl");
QName serviceName = new QName("http://example.org/sample", "MyService");
Service service = Service.create(wsdlLocation, serviceName);
This is the nastiest way to work with JBossWs. Older versions have extensive details on DII as it was then known.
JAX-WS provides a flexible plug-in framework for message processing modules, known as handlers, that may be used to extend the capabilities of a JAX-WS runtime system. #Handler Framework describes the handler framework in detail. A Service instance provides access to a HandlerResolver via a pair of getHandlerResolver/setHandlerResolver methods that may be used to configure a set of handlers on a per-service, per-port or per-protocol binding basis.
When a Service instance is used to create a proxy or a Dispatch instance then the handler resolver currently registered with the service is used to create the required handler chain. Subsequent changes to the handler resolver configured for a Service instance do not affect the handlers on previously created proxies, or Dispatch instances.
You can create an instance of a client proxy using one of getPort methods on the #Service.
/**
* The getPort method returns a proxy. A service client
* uses this proxy to invoke operations on the target
* service endpoint. The <code>serviceEndpointInterface</code>
* specifies the service endpoint interface that is supported by
* the created dynamic proxy instance.
**/
public <T> T getPort(QName portName, Class<T> serviceEndpointInterface)
{
...
}
/**
* The getPort method returns a proxy. The parameter
* <code>serviceEndpointInterface</code> specifies the service
* endpoint interface that is supported by the returned proxy.
* In the implementation of this method, the JAX-WS
* runtime system takes the responsibility of selecting a protocol
* binding (and a port) and configuring the proxy accordingly.
* The returned proxy should not be reconfigured by the client.
*
**/
public <T> T getPort(Class<T> serviceEndpointInterface)
{
...
}
The service endpoint interface (SEI) is usually generated using tools. For details see # Top Down (WSDL to Java)
A generated static #Service usually also offers typed methods to get ports. These methods also return dynamic proxies that implement the SEI.
@WebServiceClient(name = "TestEndpointService", targetNamespace = "http://org.jboss.ws/wsref",
wsdlLocation = "http://localhost.localdomain:8080/jaxws-samples-webserviceref?wsdl")
public class TestEndpointService extends Service
{
...
public TestEndpointService(URL wsdlLocation, QName serviceName) {
super(wsdlLocation, serviceName);
}
@WebEndpoint(name = "TestEndpointPort")
public TestEndpoint getTestEndpointPort()
{
return (TestEndpoint)super.getPort(TESTENDPOINTPORT, TestEndpoint.class);
}
}
There are two uses to the WebServiceRef annotation:
public class EJB3Client implements EJB3Remote { @WebServiceRef public TestEndpointService service4; @WebServiceRef public TestEndpoint port3;
define the port that should be used to resolve a container-managed port
define default Stub property settings for Stub objects
define the URL of a final WSDL document to be used
<service-ref> <service-ref-name>OrganizationService</service-ref-name> <wsdl-override>file:/wsdlRepository/organization-service.wsdl</wsdl-override> </service-ref> .. <service-ref> <service-ref-name>OrganizationService</service-ref-name> <config-name>Secure Client Config</config-name> <config-file>META-INF/jbossws-client-config.xml</config-file> <handler-chain>META-INF/jbossws-client-handlers.xml</handler-chain> </service-ref> <service-ref> <service-ref-name>SecureService</service-ref-name> <service-class-name>org.jboss.tests.ws.jaxws.webserviceref.SecureEndpointService</service-class-name> <service-qname>{http://org.jboss.ws/wsref}SecureEndpointService</service-qname> <port-info> <service-endpoint-interface>org.jboss.tests.ws.jaxws.webserviceref.SecureEndpoint</service-endpoint-interface> <port-qname>{http://org.jboss.ws/wsref}SecureEndpointPort</port-qname> <stub-property> <name>javax.xml.ws.security.auth.username</name> <value>kermit</value> </stub-property> <stub-property> <name>javax.xml.ws.security.auth.password</name> <value>thefrog</value> </stub-property> </port-info> </service-ref>
For details please see service-ref_5_0.dtd in the jboss docs directory.
Service service = Service.create(wsdlURL, serviceName); Dispatch dispatch = service.createDispatch(portName, StreamSource.class, Mode.PAYLOAD); String payload = "<ns1:ping xmlns:ns1='http://oneway.samples.jaxws.ws.test.jboss.org/'/>"; dispatch.invokeOneWay(new StreamSource(new StringReader(payload))); payload = "<ns1:feedback xmlns:ns1='http://oneway.samples.jaxws.ws.test.jboss.org/'/>"; Source retObj = (Source)dispatch.invoke(new StreamSource(new StringReader(payload)));
public void testInvokeAsync() throws Exception { URL wsdlURL = new URL("http://" + getServerHost() + ":8080/jaxws-samples-asynchronous?wsdl"); QName serviceName = new QName(targetNS, "TestEndpointService"); Service service = Service.create(wsdlURL, serviceName); TestEndpoint port = service.getPort(TestEndpoint.class); Response response = port.echoAsync("Async"); // access future String retStr = (String) response.get(); assertEquals("Async", retStr); }
@WebService (name="PingEndpoint") @SOAPBinding(style = SOAPBinding.Style.RPC) public class PingEndpointImpl { private static String feedback; .. @WebMethod @Oneway public void ping() { log.info("ping"); feedback = "ok"; } .. @WebMethod public String feedback() { log.info("feedback"); return feedback; } }
This sections describes concepts that apply equally to #Web Service Endpoints and #Web Service Clients
On the service endpoint, handlers are defined using the @HandlerChain annotation.
@WebService @HandlerChain(file = "jaxws-server-source-handlers.xml") public class SOAPEndpointSourceImpl { ... }
The location of the handler chain file supports 2 formats
1. An absolute java.net.URL in externalForm. (ex: http://myhandlers.foo.com/handlerfile1.xml)
2. A relative path from the source file or class file. (ex: bar/handlerfile1.xml)
Service service = Service.create(wsdlURL, serviceName); Endpoint port = (Endpoint)service.getPort(Endpoint.class); BindingProvider bindingProvider = (BindingProvider)port; List<Handler> handlerChain = new ArrayList<Handler>(); handlerChain.add(new LogHandler()); handlerChain.add(new AuthorizationHandler()); handlerChain.add(new RoutingHandler()); bindingProvider.getBinding().setHandlerChain(handlerChain); // important!
CommonMessageContext msgContext = MessageContextAssociation.peekMessageContext(); msgContext.setProperty(<Name>, <Value>);
An implementation may thow a SOAPFaultException
public void throwSoapFaultException() { SOAPFactory factory = SOAPFactory.newInstance(); SOAPFault fault = factory.createFault("this is a fault string!", new QName("http://foo", "FooCode")); fault.setFaultActor("mr.actor"); fault.addDetail().addChildElement("test"); throw new SOAPFaultException(fault); }
or an application specific user exception
public void throwApplicationException() throws UserException { throw new UserException("validation", 123, "Some validation error"); }
|
image/jpeg |
java.awt.Image |
|
text/xml |
javax.xml.transform.Source |
|
application/xml |
javax.xml.transform.Source |
|
application/octet-stream |
javax.activation.DataHandler |
The above table shows a list of supported endpoint parameter types. The recommended approach is to use the javax.activation.DataHandler classes to represent binary data as service endpoint parameters.
Microsoft endpoints tend to send any data as application/octet-stream. The only Java type that can easily cope with this ambiguity is javax.activation.DataHandler
MTOM enabled service implementations
package org.jboss.test.ws.jaxws.samples.xop.doclit; import javax.ejb.Remote; import javax.jws.WebService; import javax.jws.soap.SOAPBinding; import javax.xml.ws.BindingType; @Remote @WebService(targetNamespace = "http://org.jboss.ws/xop/doclit") @SOAPBinding(style = SOAPBinding.Style.DOCUMENT, parameterStyle = SOAPBinding.ParameterStyle.BARE) @BindingType(value="http://schemas.xmlsoap.org/wsdl/soap/http?mtom=true") (1) public interface MTOMEndpoint { [...] }
[...] Service service = Service.create(wsdlURL, serviceName); port = service.getPort(MTOMEndpoint.class); // enable MTOM binding = (SOAPBinding)((BindingProvider)port).getBinding(); binding.setMTOMEnabled(true);
WS-I Attachment Profile 1.0 defines mechanism to reference MIME attachment parts using swaRef. In this mechanism the content of XML element of type wsi:swaRef is sent as MIME attachment and the element inside SOAP Body holds the reference to this attachment in the CID URI scheme as defined by RFC 2111.
/** * Payload bean that will use SwaRef encoding */ @XmlRootElement public class DocumentPayload { private DataHandler data; public DocumentPayload() { } public DocumentPayload(DataHandler data) { this.data = data; } @XmlElement @XmlAttachmentRef public DataHandler getData() { return data; } public void setData(DataHandler data) { this.data = data; } }
@WebService public interface DocWrappedEndpoint { @WebMethod DocumentPayload beanAnnotation(DocumentPayload dhw, String test); @WebMethod @XmlAttachmentRef DataHandler parameterAnnotation(@XmlAttachmentRef DataHandler data, String test); }
The message would then refer to the attachment part by CID:
<env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'> <env:Header/> <env:Body> <ns2:parameterAnnotation xmlns:ns2='http://swaref.samples.jaxws.ws.test.jboss.org/'> <arg0>cid:0-1180017772935-32455963@ws.jboss.org</arg0> <arg1>Wrapped test</arg1> </ns2:parameterAnnotation> </env:Body> </env:Envelope>
<element name="data" type="wsi:swaRef" xmlns:wsi="http://ws-i.org/profiles/basic/1.1/xsd"/>
Any wsi:swaRef schema type would then be mapped to DataHandler.
Exposing an already existing EJB3 bean as a Web Service
Providing a new service, and you want the contract to be generated for you
The following JAX-WS command line tools are included in JBossWS:
|
Command |
Description |
|
Generates JAX-WS portable artifacts, and provides the abstract contract. Used for bottom-up development. |
|
|
Consumes the abstract contract (WSDL and Schema files), and produces artifacts for both a server and client. Used for top-down and client development |
|
|
Executes a Java client (has a main method) using the JBossWS classpath. |
This can be as simple as creating a single class:
package echo; @javax.jws.WebService public class Echo { public String echo(String input) { return input; } }
This is the primary purpose of the wsprovide tool, to generate portable JAX-WS artifacts. Additionally, it can be used to "provide" the abstract contract (WSDL file) for your service. This can be obtained by invoking wsprovide using the "-w" option:
$ javac -d . -classpath jboss-jaxws.jar Echo.java $ wsprovide -w echo.Echo Generating WSDL: EchoService.wsdl Writing Classes: echo/jaxws/Echo.class echo/jaxws/EchoResponse.class
Inspecting the WSDL reveals a service called EchoService:
<service name='EchoService'> <port binding='tns:EchoBinding' name='EchoPort'> <soap:address location='REPLACE_WITH_ACTUAL_URL'/> </port> </service>
As expected, this service defines one operation, "echo":
<portType name='Echo'> <operation name='echo' parameterOrder='echo'> <input message='tns:Echo_echo'/> <output message='tns:Echo_echoResponse'/> </operation> </portType>
Remember that when deploying on JBossWS you do not need to run this tool. You only need it for generating portable artifacts and/or the abstract contract for your service.
Let's create a POJO endpoint for deployment on JBoss AS. A simple web.xml needs to be created:
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4"> <servlet> <servlet-name>Echo</servlet-name> <servlet-class>echo.Echo</servlet-class> </servlet> <servlet-mapping> <servlet-name>Echo</servlet-name> <url-pattern>/Echo</url-pattern> </servlet-mapping> </web-app>
The web.xml and the single class can now be used to create a war:
$ mkdir -p WEB-INF/classes $ cp -rp echo WEB-INF/classes/ $ cp web.xml WEB-INF $ jar cvf echo.war WEB-INF added manifest adding: WEB-INF/(in = 0) (out= 0)(stored 0%) adding: WEB-INF/classes/(in = 0) (out= 0)(stored 0%) adding: WEB-INF/classes/echo/(in = 0) (out= 0)(stored 0%) adding: WEB-INF/classes/echo/Echo.class(in = 340) (out= 247)(deflated 27%) adding: WEB-INF/web.xml(in = 576) (out= 271)(deflated 52%)
The war can then be deployed:
cp echo.war /usr/local/jboss-4.2.0.GA-ejb3/server/default/deploy
This will internally invoke wsprovide, which will generate the WSDL. If deployment was successful, and you are using the default settings, it should be available here: http://localhost:8080/echo/Echo?wsdl
For a portable JAX-WS deployment, the wrapper classes generated earlier could be added to the deployment.
The top-down development strategy begins with the abstract contract for the service, which includes the WSDL file and zero or more schema files. The wsconsume tool is then used to consume this contract, and produce annotated Java classes (and optionally sources) that define it.
wsconsume seems to have a problem with symlinks on unix systems
Using the WSDL file from the bottom-up example, a new Java implementation that adheres to this service can be generated. The "-k" option is passed to wsconsume to preserve the Java source files that are generated, instead of providing just classes:
$ wsconsume -k EchoService.wsdl echo/Echo.java echo/EchoResponse.java echo/EchoService.java echo/Echo_Type.java echo/ObjectFactory.java echo/package-info.java echo/Echo.java echo/EchoResponse.java echo/EchoService.java echo/Echo_Type.java echo/ObjectFactory.java echo/package-info.java
The following table shows the purpose of each generated file:
|
File |
Purpose |
|
Echo.java |
Service Endpoint Interface |
|
Echo_Type.java |
Wrapper bean for request message |
|
EchoResponse.java |
Wrapper bean for response message |
|
ObjectFactory.java |
JAXB XML Registry |
|
package-info.java |
Holder for JAXB package annotations |
|
EchoService.java |
Used only by JAX-WS clients |
Examining the Service Endpoint Interface reveals annotations that are more explicit than in the class written by hand in the bottom-up example, however, these evaluate to the same contract:
@WebService(name = "Echo", targetNamespace = "http://echo/")
public interface Echo {
@WebMethod
@WebResult(targetNamespace = "")
@RequestWrapper(localName = "echo", targetNamespace = "http://echo/", className = "echo.Echo_Type")
@ResponseWrapper(localName = "echoResponse", targetNamespace = "http://echo/", className = "echo.EchoResponse")
public String echo(
@WebParam(name = "arg0", targetNamespace = "")
String arg0);
}
The only missing piece (besides the packaging) is the implementation class, which can now be written, using the above interface.
package echo;
@javax.jws.WebService(endpointInterface="echo.Echo")
public class EchoImpl implements Echo
{
public String echo(String arg0)
{
return arg0;
}
}
Let's repeat the process of the top-down section, although using the deployed WSDL, instead of the one generated offline by wsprovide. The reason why we do this is just to get the right value for soap:address. This value must be computed at deploy time, since it is based on container configuration specifics. You could of course edit the WSDL file yourself, although you need to ensure that the path is correct.
Offline version:
<service name='EchoService'> <port binding='tns:EchoBinding' name='EchoPort'> <soap:address location='REPLACE_WITH_ACTUAL_URL'/> </port> </service>
Online version:
<service name="EchoService"> <port binding="tns:EchoBinding" name="EchoPort"> <soap:address location="http://localhost.localdomain:8080/echo/Echo"/> </port> </service>
Using the online deployed version with wsconsume:
$ wsconsume -k http://localhost:8080/echo/Echo?wsdl echo/Echo.java echo/EchoResponse.java echo/EchoService.java echo/Echo_Type.java echo/ObjectFactory.java echo/package-info.java echo/Echo.java echo/EchoResponse.java echo/EchoService.java echo/Echo_Type.java echo/ObjectFactory.java echo/package-info.java
The one class that was not examined in the top-down section, was EchoService.java. Notice how it stores the location the WSDL was obtained from.
@WebServiceClient(name = "EchoService", targetNamespace = "http://echo/", wsdlLocation = "http://localhost:8080/echo/Echo?wsdl")
public class EchoService extends Service
{
private final static URL ECHOSERVICE_WSDL_LOCATION;
static {
URL url = null;
try {
url = new URL("http://localhost:8080/echo/Echo?wsdl");
} catch (MalformedURLException e) {
e.printStackTrace();
}
ECHOSERVICE_WSDL_LOCATION = url;
}
public EchoService(URL wsdlLocation, QName serviceName) {
super(wsdlLocation, serviceName);
}
public EchoService() {
super(ECHOSERVICE_WSDL_LOCATION, new QName("http://echo/", "EchoService"));
}
@WebEndpoint(name = "EchoPort")
public Echo getEchoPort() {
return (Echo)super.getPort(new QName("http://echo/", "EchoPort"), Echo.class);
}
}
As you can see, this generated class extends the main client entry point in JAX-WS, javax.xml.ws.Service. While you can use Service directly, this is far simpler since it provides the configuration info for you. The only method we really care about is the getEchoPort() method, which returns an instance of our Service Endpoint Interface. Any WS operation can then be called by just invoking a method on the returned interface.
It's not recommended to refer to a remote WSDL URL in a production application. This causes network I/O every time you instantiate the Service Object. Instead, use the tool on a saved local copy, or use the URL version of the constructor to provide a new WSDL location.
All that is left to do, is write and compile the client:
import echo.*;
..
public class EchoClient
{
public static void main(String args[])
{
if (args.length != 1)
{
System.err.println("usage: EchoClient <message>");
System.exit(1);
}
EchoService service = new EchoService();
Echo echo = service.getEchoPort();
System.out.println("Server said: " + echo.echo(args[0]));
}
}
It can then be easily executed using the wsrunclient tool. This is just a convenience tool that invokes java with the needed classpath:
$ wsrunclient EchoClient 'Hello World!' Server said: Hello World!
It is easy to change the endpoint address of your operation at runtime, setting the ENDPOINT_ADDRESS_PROPERTY as shown below:
...
EchoService service = new EchoService();
Echo echo = service.getEchoPort();
/* Set NEW Endpoint Location */
String endpointURL = "http://NEW_ENDPOINT_URL";
BindingProvider bp = (BindingProvider)echo;
bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpointURL);
System.out.println("Server said: " + echo.echo(args[0]));
...
An introduction to binding customizations:
The schema for the binding customization files can be found here:
This section describes how WS-Addressing can be used to provide a staful service endpoint.
WS-Addressing is defined by a combination of the following specifications from the W3C Candidate Recommendation 17 August 2005. The WS-Addressing API is standardized by JSR-261 - Java API for XML Web Services Addressing
@WebService(name = "StatefulEndpoint", targetNamespace = "http://org.jboss.ws/samples/wsaddressing", serviceName = "TestService") @EndpointConfig(configName = "Standard WSAddressing Endpoint") @HandlerChain(file = "WEB-INF/jaxws-handlers.xml") @SOAPBinding(style = SOAPBinding.Style.RPC) public class StatefulEndpointImpl implements StatefulEndpoint, ServiceLifecycle { @WebMethod public void addItem(String item) { ... } @WebMethod public void checkout() { ... } @WebMethod public String getItems() { ... } }
It uses the JAX-WS Endpoint Configuration# Standard WSAddressing Endpoint to enable the server side addressing handler. It processes the incomming WS-Addressing header elements and provides access to them through the JSR-261 API.
The endpoint handler chain
<handler-chains xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee javaee_web_services_1_2.xsd"> <handler-chain> <protocol-bindings>##SOAP11_HTTP</protocol-bindings> <handler> <handler-name>Application Server Handler</handler-name> <handler-class>org.jboss.test.ws.jaxws.samples.wsaddressing.ServerHandler</handler-class> </handler> </handler-chain> </handler-chains>
defines an application specific hander that assignes/processes stateful client ids.
The client sets a custom handler chain in the binding
Service service = Service.create(wsdlURL, serviceName); port1 = (StatefulEndpoint)service.getPort(StatefulEndpoint.class); BindingProvider bindingProvider = (BindingProvider)port1; List<Handler> customHandlerChain = new ArrayList<Handler>(); customHandlerChain.add(new ClientHandler()); customHandlerChain.add(new WSAddressingClientHandler()); bindingProvider.getBinding().setHandlerChain(customHandlerChain);
A client connecting to the stateful endpoint
public class AddressingStatefulTestCase extends JBossWSTest { public void testAddItem() throws Exception { port1.addItem("Ice Cream"); port1.addItem("Ferrari"); port2.addItem("Mars Bar"); port2.addItem("Porsche"); } public void testGetItems() throws Exception { String items1 = port1.getItems(); assertEquals("[Ice Cream, Ferrari]", items1); String items2 = port2.getItems(); assertEquals("[Mars Bar, Porsche]", items2); } }
Below you see the SOAP messages that are beeing exchanged.
<env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'> <env:Header xmlns:wsa='http://schemas.xmlsoap.org/ws/2004/08/addressing'> <wsa:To>uri:jbossws-samples-wsaddr/TestService</wsa:To> <wsa:Action>http://org.jboss.ws/addressing/stateful/action</wsa:Action> <wsa:ReferenceParameters> <ns1:clientid xmlns:ns1='http://somens'>clientid-1</ns1:clientid> </wsa:ReferenceParameters> </env:Header> <env:Body> <ns1:addItem xmlns:ns1='http://org.jboss.ws/samples/wsaddr'> <String_1>Ice Cream</String_1> </ns1:addItem> </env:Body> </env:Envelope> <env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'> <env:Header xmlns:wsa='http://schemas.xmlsoap.org/ws/2004/08/addressing'> <wsa:To>http://www.w3.org/2005/08/addressing/anonymous</wsa:To> <wsa:Action>http://org.jboss.ws/addressing/stateful/actionReply</wsa:Action> <ns1:clientid xmlns:ns1='http://somens'>clientid-1</ns1:clientid> </env:Header> <env:Body> <ns1:addItemResponse xmlns:ns1='http://org.jboss.ws/samples/wsaddr'/> </env:Body> </env:Envelope> ... <env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'> <env:Header xmlns:wsa='http://schemas.xmlsoap.org/ws/2004/08/addressing'> <wsa:To>uri:jbossws-samples-wsaddr/TestService</wsa:To> <wsa:Action>http://org.jboss.ws/addressing/stateful/action</wsa:Action> <wsa:ReferenceParameters> <ns1:clientid xmlns:ns1='http://somens'>clientid-1</ns1:clientid> </wsa:ReferenceParameters> </env:Header> <env:Body> <ns1:getItems xmlns:ns1='http://org.jboss.ws/samples/wsaddr'/> </env:Body> </env:Envelope> <env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'> <env:Header xmlns:wsa='http://schemas.xmlsoap.org/ws/2004/08/addressing'> <wsa:To>http://www.w3.org/2005/08/addressing/anonymous</wsa:To> <wsa:Action>http://org.jboss.ws/addressing/stateful/actionReply</wsa:Action> <ns1:clientid xmlns:ns1='http://somens'>clientid-1</ns1:clientid> </env:Header> <env:Body> <ns1:getItemsResponse xmlns:ns1='http://org.jboss.ws/samples/wsaddr'> <result>[Ice Cream, Ferrari]</result> </ns1:getItemsResponse> </env:Body> </env:Envelope>
WS-Eventing is defined by the combination of the following specifications:
The following section will introduce the main eventing actors and their responsiblities.
The original eventing specification builds upon WS-Addressing 2004/08. JBossWS however decided to stick to the latest version, which is the W3C candidate release.
With
JAX-WS the event source setup has actually become quiet easy. All you
need to do is to subclass your endpoint implementation from AbstractEventSourceEndpoint and a subscription manager from AbstractSubscriptionManagerEndpoint and finally point that implementation to a event source specific WSDL.
package org.jboss.test.ws.jaxws.samples.wseventing;
..
import javax.jws.WebService;
import org.jboss.logging.Logger;
import org.jboss.ws.annotation.EndpointConfig;
import org.jboss.ws.extensions.eventing.jaxws.AbstractEventSourceEndpoint;
/**
* @author Heiko.Braun@jboss.org
* @version $Id$
* @since 18.01.2007
*/
@WebService( (1)
name = "EventSource",
portName = "EventSourcePort",
targetNamespace = "http://schemas.xmlsoap.org/ws/2004/08/eventing",
wsdlLocation = "/WEB-INF/wsdl/sysmon.wsdl", (2)
endpointInterface = "org.jboss.ws.extensions.eventing.jaxws.EventSourceEndpoint")
@EndpointConfig(configName = "Standard WSAddressing Endpoint") (3)
public class SysmonRegistrationEndpoint extends AbstractEventSourceEndpoint { (4)
private static final Logger log = Logger.getLogger(SysmonRegistrationEndpoint.class);
protected Logger getLogger()
{
return log;
}
}
Of course we need a @WebService annotation
It's important to override the WSDL here
You need to tell JBossWS that it requires WS-Addressing for this endpoint
Subclass a predefined implementation that knows how to delegate to the actual eventing service implementation
The following excerpt shows the relevant WSDL details that describe an event source.
<?xml version="1.0" encoding="UTF-8"?> <wsdl:definitions targetNamespace="http://www.jboss.org/sysmon" xmlns:tns="http://www.jboss.org/sysmon" xmlns:wse='http://schemas.xmlsoap.org/ws/2004/08/eventing' xmlns:wsdl='http://schemas.xmlsoap.org/wsdl/' xmlns:wsa10='http://www.w3.org/2005/08/addressing' xmlns:xs='http://www.w3.org/2001/XMLSchema' xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"> <wsdl:import (1) namespace='http://schemas.xmlsoap.org/ws/2004/08/eventing' location='jbwse.wsdl' /> <wsdl:types> <xs:schema targetNamespace='http://schemas.xmlsoap.org/ws/2004/08/eventing'> (2) <xs:include schemaLocation='jbwse.xsd'/> </xs:schema> (3) <xs:schema targetNamespace="http://www.jboss.org/sysmon" elementFormDefault="qualified" blockDefault="#all"> <xs:element name="SystemStatus"> <xs:complexType> <xs:sequence> <xs:element name="Time " type="xs:dateTime"/> <xs:element name="HostName" type="xs:string"/> <xs:element name="HostAddress" type="xs:string"/> <xs:element name="ActiveThreadCount" type="xs:int"/> <xs:element name="FreeMemory" type="xs:string"/> <xs:element name="MaxMemory" type="xs:string"/> </xs:sequence> </xs:complexType> </xs:element> </xs:schema> </wsdl:types> <wsdl:message name='SystemInfoMsg'> <wsdl:part name='body' element='tns:SystemStatus'/> </wsdl:message> (4) <wsdl:portType name='SystemInfo' wse:EventSource='true'> <wsdl:operation name='SysmonOp'> <wsdl:output message='tns:SystemInfoMsg'/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="SystemInfoBinding" type="tns:SystemInfo"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="SysmonOp"> <soap:operation soapAction=""/> <wsdl:output> <soap:body use="literal"/> </wsdl:output> </wsdl:operation> </wsdl:binding> </wsdl:definitions>
Import the default eventing WSDL, that includes service and port declarations.
Include the default eventing Types
Specifiy the notitification message schema.
java:/EventDispatcher
The event dispatcher interface:
public interface EventDispatcher { void dispatch(URI eventSourceNS, Element payload); }
(1) URI eventSourceURI = new URI("http://http://www.jboss.org/sysmon/SystemInfo"); (2) Element payload = DOMUtils.parse("SOME XML STRING"); try { InitialContext iniCtx = getInitialContext(); (3) EventDispatcher delegate = (EventDispatcher) iniCtx.lookup(EventingConstants.DISPATCHER_JNDI_NAME); (4) delegate.dispatch(eventSourceURI, payload); } catch (Exception e) { // }
jboss.ws.eventing:service=SubscriptionManager
corePoolSize - average number of idle threads
maximumPoolSize - maximum number of threads
eventKeepAlive - keep alive before an undelivered event message is discarded.
This chapter describes how to use WS-Security to sign and encrypt a simple SOAP message.
WS-Security is defined by the combination of the following specifications:
JBossWS uses handlers to identify ws-security encoded requests and invoke the security components to sign and encrypt messages. In order to enable security processing, the client and server side need to include a corressponding handler configuration. The preferred way is to reference a predefined JAX-WS Endpoint Configuration or JAX-WS Client Configuration respectively.
You need to setup both the endpoint configuration and the WSSE declarations. That's two separate steps.
<jboss-ws-security xmlns="http://www.jboss.com/ws-security/config" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.jboss.com/ws-security/config http://www.jboss.com/ws-security/schema/jboss-ws-security_1_0.xsd"> (1) <key-store-file>WEB-INF/wsse.keystore</key-store-file> (2) <key-store-password>jbossws</key-store-password> (3) <trust-store-file>WEB-INF/wsse.truststore</trust-store-file> (4) <trust-store-password>jbossws</trust-store-password> (5) <config> (6) <sign type="x509v3" alias="wsse"/> (7) <requires> (8) <signature/> </requires> </config> </jboss-ws-security>
By default an endpoint does not use the WS-Security configuration. Use the proprietary @EndpointConfig annotation to set the config name. See JAX-WS_Endpoint_Configuration for the list of available config names.
@WebService
@EndpointConfig(configName = "Standard WSSecurity Endpoint")
public class HelloJavaBean
{
...
}
<jboss-ws-security xmlns="http://www.jboss.com/ws-security/config" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.jboss.com/ws-security/config http://www.jboss.com/ws-security/schema/jboss-ws-security_1_0.xsd"> (1) <config> (2) <sign type="x509v3" alias="wsse"/> (3) <requires> (4) <signature/> </requires> </config> </jboss-ws-security>
Here is an excerpt from the JBossWS samples:
<sysproperty key="org.jboss.ws.wsse.keyStore" value="${tests.output.dir}/resources/jaxrpc/samples/wssecurity/wsse.keystore"/> <sysproperty key="org.jboss.ws.wsse.trustStore" value="${tests.output.dir}/resources/jaxrpc/samples/wssecurity/wsse.truststore"/> <sysproperty key="org.jboss.ws.wsse.keyStorePassword" value="jbossws"/> <sysproperty key="org.jboss.ws.wsse.trustStorePassword" value="jbossws"/> <sysproperty key="org.jboss.ws.wsse.keyStoreType" value="jks"/> <sysproperty key="org.jboss.ws.wsse.trustStoreType" value="jks"/>
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"> <env:Header> <wsse:Security env:mustUnderstand="1" ...> <wsu:Timestamp wsu:Id="timestamp">...</wsu:Timestamp> <wsse:BinarySecurityToken ...> ... </wsse:BinarySecurityToken> <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> ... </ds:Signature> </wsse:Security> </env:Header> <env:Body wsu:Id="element-1-1140197309843-12388840" ...> <ns1:echoUserType xmlns:ns1="http://org.jboss.ws/samples/wssecurity"> <UserType_1 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <msg>Kermit</msg> </UserType_1> </ns1:echoUserType> </env:Body> </env:Envelope>
The information below has originaly been provided by The Legion of the Bouncy Castle.
The provider can be configured as part of your environment via static registration by adding an entry to the java.security properties file (found in $JAVA_HOME/jre/lib/security/java.security, where $JAVA_HOME is the location of your JDK/JRE distribution). You'll find detailed instructions in the file but basically it comes down to adding a line:
security.provider.<n>=org.bouncycastle.jce.provider.BouncyCastleProvider
Where <n> is the preference you want the provider at.
Issues may arise if the Sun provided providers are not first.
Where you put the jar is mostly up to you, although with jdk1.4 the best (and in some cases only) place to have it is in $JAVA_HOME/jre/lib/ext. Under Windows there will normally be a JRE and a JDK install of Java if you think you have installed it correctly and it still doesn't work chances are you have added the provider to the installation not being used.
Support for the WS-Coordination, WS-AtomicTransaction and WS-BusinessActivity specifications will be provided by technology recently acquired from Arjuna Technologies Ltd. This technology will be present within the JBoss Transactions 4.2.1 release. Further information can be obtained from the JBoss Transactions Project
Let us look at the individual configuration items that can be changed.
<!-- Datasource to Database--> <attribute name="DataSourceUrl">java:/DefaultDS</attribute>
<!-- Should all tables be created on Start--> <attribute name="CreateOnStart">false</attribute> <!-- Should all tables be dropped on Stop--> <attribute name="DropOnStop">true</attribute> <!-- Should all tables be dropped on Start--> <attribute name="DropOnStart">false</attribute>
JAXR Connection Factory to be bound in JNDI. (Should it be bound? and under what name?)
<!-- Should I bind a Context to which JaxrConnectionFactory bound--> <attribute name="ShouldBindJaxr">true</attribute> <!-- Context to which JaxrConnectionFactory to bind to. If you have remote clients, please bind it to the global namespace(default behavior). To just cater to clients running on the same VM as JBoss, change to java:/JAXR --> <attribute name="BindJaxr">JAXR</attribute>
Add authorized users to access the jUDDI registry. (Add a sql insert statement in a single line)
Look at the script META-INF/ddl/juddi_data.ddl for more details. Example for a user 'jboss' INSERT INTO PUBLISHER (PUBLISHER_ID,PUBLISHER_NAME, EMAIL_ADDRESS,IS_ENABLED,IS_ADMIN) VALUES ('jboss','JBoss User','jboss@xxx','true','true');
javax.xml.registry.ConnectionFactoryClass=org.apache.ws.scout.registry.ConnectionFactoryImpl jaxr.query.url=http://localhost:8080/juddi/inquiry jaxr.publish.url=http://localhost:8080/juddi/publish juddi.proxy.transportClass=org.jboss.jaxr.juddi.transport.SaajTransport
You can pass the System Properties to the JVM in the following ways:
System.setProperty(propertyname, propertyvalue);
javax.xml.registry.RegistryService From J2EE 1.4 JavaDoc: "This is the principal interface implemented by a JAXR provider. A registry client can get this interface from a Connection to a registry. It provides the methods that are used by the client to discover various capability specific interfaces implemented by the JAXR provider."
javax.xml.registry.BusinessLifeCycleManager From J2EE 1.4 JavaDoc: "The BusinessLifeCycleManager interface, which is exposed by the Registry Service, implements the life cycle management functionality of the Registry as part of a business level API. Note that there is no authentication information provided, because the Connection interface keeps that state and context on behalf of the client."
javax.xml.registry.BusinessQueryManager From J2EE 1.4 JavaDoc: "The BusinessQueryManager interface, which is exposed by the Registry Service, implements the business style query interface. It is also referred to as the focused query interface."
Let us now look at some of the common programming tasks performed while using the JAXR API:
Getting a JAXR Connection to the registry.
String queryurl = System.getProperty("jaxr.query.url", "http://localhost:8080/juddi/inquiry");
String puburl = System.getProperty("jaxr.publish.url", "http://localhost:8080/juddi/publish");
..
Properties props = new Properties();
props.setProperty("javax.xml.registry.queryManagerURL", queryurl);
props.setProperty("javax.xml.registry.lifeCycleManagerURL", puburl);
String transportClass = System.getProperty("juddi.proxy.transportClass", "org.jboss.jaxr.juddi.transport.SaajTransport");
System.setProperty("juddi.proxy.transportClass", transportClass);
// Create the connection, passing it the configuration properties
factory = ConnectionFactory.newInstance();
factory.setProperties(props);
connection = factory.createConnection();
Authentication with the registry.
/**
* Does authentication with the uddi registry
*/
protected void login() throws JAXRException
{
PasswordAuthentication passwdAuth = new PasswordAuthentication(userid, passwd.toCharArray());
Set creds = new HashSet();
creds.add(passwdAuth);
connection.setCredentials(creds);
}
Save a Business
/**
* Creates a Jaxr Organization with 1 or more services
*/
protected Organization createOrganization(String orgname) throws JAXRException
{
Organization org = blm.createOrganization(getIString(orgname));
org.setDescription(getIString("JBoss Inc"));
Service service = blm.createService(getIString("JBOSS JAXR Service"));
service.setDescription(getIString("Services of XML Registry"));
//Create serviceBinding
ServiceBinding serviceBinding = blm.createServiceBinding();
serviceBinding.setDescription(blm.createInternationalString("Test Service Binding"));
//Turn validation of URI off
serviceBinding.setValidateURI(false);
serviceBinding.setAccessURI("http://testjboss.org");
..
// Add the serviceBinding to the service
service.addServiceBinding(serviceBinding);
User user = blm.createUser();
org.setPrimaryContact(user);
PersonName personName = blm.createPersonName("Anil S");
TelephoneNumber telephoneNumber = blm.createTelephoneNumber();
telephoneNumber.setNumber("111-111-7777");
telephoneNumber.setType(null);
PostalAddress address = blm.createPostalAddress("111", "My Drive", "BuckHead", "GA", "USA", "1111-111", "");
Collection postalAddresses = new ArrayList();
postalAddresses.add(address);
Collection emailAddresses = new ArrayList();
EmailAddress emailAddress = blm.createEmailAddress("anil@apache.org");
emailAddresses.add(emailAddress);
Collection numbers = new ArrayList();
numbers.add(telephoneNumber);
user.setPersonName(personName);
user.setPostalAddresses(postalAddresses);
user.setEmailAddresses(emailAddresses);
user.setTelephoneNumbers(numbers);
ClassificationScheme cScheme = getClassificationScheme("ntis-gov:naics", "");
Key cKey = blm.createKey("uuid:C0B9FE13-324F-413D-5A5B-2004DB8E5CC2");
cScheme.setKey(cKey);
Classification classification = blm.createClassification(cScheme, "Computer Systems Design and Related Services", "5415");
org.addClassification(classification);
ClassificationScheme cScheme1 = getClassificationScheme("D-U-N-S", "");
Key cKey1 = blm.createKey("uuid:3367C81E-FF1F-4D5A-B202-3EB13AD02423");
cScheme1.setKey(cKey1);
ExternalIdentifier ei = blm.createExternalIdentifier(cScheme1, "D-U-N-S number", "08-146-6849");
org.addExternalIdentifier(ei);
org.addService(service);
return org;
}
Query a Business
/**
* Locale aware Search a business in the registry
*/
public void searchBusiness(String bizname) throws JAXRException
{
try
{
// Get registry service and business query manager
this.getJAXREssentials();
// Define find qualifiers and name patterns
Collection findQualifiers = new ArrayList();
findQualifiers.add(FindQualifier.SORT_BY_NAME_ASC);
Collection namePatterns = new ArrayList();
String pattern = "%" + bizname + "%";
LocalizedString ls = blm.createLocalizedString(Locale.getDefault(), pattern);
namePatterns.add(ls);
// Find based upon qualifier type and values
BulkResponse response = bqm.findOrganizations(findQualifiers, namePatterns, null, null, null, null);
// check how many organisation we have matched
Collection orgs = response.getCollection();
if (orgs == null)
{
log.debug(" -- Matched 0 orgs");
}
else
{
log.debug(" -- Matched " + orgs.size() + " organizations -- ");
// then step through them
for (Iterator orgIter = orgs.iterator(); orgIter.hasNext();)
{
Organization org = (Organization)orgIter.next();
log.debug("Org name: " + getName(org));
log.debug("Org description: " + getDescription(org));
log.debug("Org key id: " + getKey(org));
checkUser(org);
checkServices(org);
}
}
}
finally
{
connection.close();
}
}
For more examples of code using the JAXR API, please refer to the resources in the Resources Section.
WS-Policy is defined by the combination of the following specifications:
* <ulink url="http://www.w3.org/Submission/WS-Policy/"> WS-Policy specification</ulink> * <ulink url="http://www.w3.org/Submission/WS-PolicyAttachment/"> WS-Policy-Attachment specification</ulink>
@WebService(name = "Hello", targetNamespace = "http://org.jboss.ws/samples/wssecuritypolicy", wsdlLocation="WEB-INF/wsdl/HelloService.wsdl") @SOAPBinding(style = SOAPBinding.Style.RPC) public class HelloJavaBean { private Logger log = Logger.getLogger(HelloJavaBean.class); .. @WebMethod public UserType echoUserType(@WebParam(name = "user") UserType in0) { log.info(in0); return in0; } } <?xml version="1.0" encoding="UTF-8"?> <definitions name='HelloService' targetNamespace='http://org.jboss.ws/samples/wssecuritypolicy' xmlns='http://schemas.xmlsoap.org/wsdl/' xmlns:ns1='http://org.jboss.ws/samples/wssecurity' xmlns:soap='http://schemas.xmlsoap.org/wsdl/soap/' xmlns:tns='http://org.jboss.ws/samples/wssecuritypolicy' xmlns:wsp='http://schemas.xmlsoap.org/ws/2004/09/policy' xmlns:xsd='http://www.w3.org/2001/XMLSchema'> <types> <xs:schema targetNamespace='http://org.jboss.ws/samples/wssecurity' version='1.0' xmlns:xs='http://www.w3.org/2001/XMLSchema'> <xs:complexType name='UserType'> <xs:sequence> <xs:element minOccurs='0' name='msg' type='xs:string'/> </xs:sequence> </xs:complexType> </xs:schema> </types> <wsp:Policy wsu:Id='X509EndpointPolicy' xmlns:wsu='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd'> <wsp:All> <sp:jboss-ws-security xmlns:sp='http://www.jboss.com/ws-security/schema/jboss-ws-security_1_0.xsd'> <sp:key-store-file>WEB-INF/wsse.keystore</sp:key-store-file> <sp:key-store-password>jbossws</sp:key-store-password> <sp:trust-store-file>WEB-INF/wsse.truststore</sp:trust-store-file> <sp:trust-store-password>jbossws</sp:trust-store-password> <sp:config> <sp:encrypt alias='wsse' type='x509v3'/> <sp:requires> <sp:encryption/> </sp:requires> </sp:config> </sp:jboss-ws-security> </wsp:All> </wsp:Policy> <message name='Hello_echoUserType'> <part name='user' type='ns1:UserType'/> </message> <message name='Hello_echoUserTypeResponse'> <part name='return' type='ns1:UserType'/> </message> <portType name='Hello'> <operation name='echoUserType' parameterOrder='user'> <input message='tns:Hello_echoUserType'/> <output message='tns:Hello_echoUserTypeResponse'/> </operation> </portType> <binding name='HelloBinding' type='tns:Hello'> <wsp:PolicyReference URI='#X509EndpointPolicy'/> <soap:binding style='rpc' transport='http://schemas.xmlsoap.org/soap/http'/> <operation name='echoUserType'> <soap:operation soapAction=''/> <input> <soap:body namespace='http://org.jboss.ws/samples/wssecuritypolicy' use='literal'/> </input> <output> <soap:body namespace='http://org.jboss.ws/samples/wssecuritypolicy' use='literal'/> </output> </operation> </binding> <service name='HelloService'> <port binding='tns:HelloBinding' name='HelloPort'> <soap:address location='REPLACE_WITH_ACTUAL_URL'/> </port> </service> </definitions>
/** @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface PolicyAttachment { Policy[] value(); } ... @Retention(RetentionPolicy.RUNTIME) public @interface Policy { public String policyFileLocation(); public PolicyScopeLevel scope(); }
And here you have the previous section example re-implemented using annotations and xml policy file:
@WebService(name = "Hello", targetNamespace = "http://org.jboss.ws/samples/wssecurityAnnotatedpolicy") @PolicyAttachment({@Policy( policyFileLocation="WEB-INF/Policy.xml", scope = PolicyScopeLevel.WSDL_PORT ) }) @SOAPBinding(style = SOAPBinding.Style.RPC) public class HelloJavaBean { private Logger log = Logger.getLogger(HelloJavaBean.class); @WebMethod public UserType echoUserType(@WebParam(name = "user") UserType in0) { log.info(in0); return in0; } } <?xml version="1.0" encoding="UTF-8"?> ... <wsp:Policy wsu:Id="X509EndpointPolicy" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"> <wsp:ExactlyOne> <wsp:All> <sp:jboss-ws-security xmlns:sp="http://www.jboss.com/ws-security/schema/jboss-ws-security_1_0.xsd"> <sp:key-store-file>WEB-INF/wsse.keystore</sp:key-store-file> <sp:key-store-password>jbossws</sp:key-store-password> <sp:trust-store-file>WEB-INF/wsse.truststore</sp:trust-store-file> <sp:trust-store-password>jbossws</sp:trust-store-password> <sp:config> <sp:encrypt type="x509v3" alias="wsse"/> <sp:requires> <sp:encryption/> </sp:requires> </sp:config> </sp:jboss-ws-security> </wsp:All> </wsp:ExactlyOne> </wsp:Policy>
This section describes propriatary JBoss extensions to JAX-WS.
For the set of standard annotations, please have a look at JAX-WS Annotations
/** * Defines an endpoint or client configuration. * This annotation is valid on an endpoint implementaion bean or a SEI. * * @author Heiko.Braun@jboss.org * @since 16.01.2007 */ @Retention(value = RetentionPolicy.RUNTIME) @Target(value = { ElementType.TYPE }) public @interface EndpointConfig { ... /** * The optional config-name element gives the configuration name that must be present in * the configuration given by element config-file. * * Server side default: Standard Endpoint * Client side default: Standard Client */ String configName() default ""; ... /** * The optional config-file element is a URL or resource name for the configuration. * * Server side default: standard-jaxws-endpoint-config.xml * Client side default: standard-jaxws-client-config.xml */ String configFile() default ""; }
/** * Provides web context specific meta data to EJB based web service endpoints. * * @author thomas.diesler@jboss.org * @since 26-Apr-2005 */ @Retention(value = RetentionPolicy.RUNTIME) @Target(value = { ElementType.TYPE }) public @interface WebContext { ... /** * The contextRoot element specifies the context root that the web service endpoint is deployed to. * If it is not specified it will be derived from the deployment short name. * * Applies to server side port components only. */ String contextRoot() default ""; ... /** * The virtual hosts that the web service endpoint is deployed to. * * Applies to server side port components only. */ String[] virtualHosts() default {}; /** * Relative path that is appended to the contextRoot to form fully qualified * endpoint address for the web service endpoint. * * Applies to server side port components only. */ String urlPattern() default ""; /** * The authMethod is used to configure the authentication mechanism for the web service. * As a prerequisite to gaining access to any web service which are protected by an authorization * constraint, a user must have authenticated using the configured mechanism. * * Legal values for this element are "BASIC", or "CLIENT-CERT". */ String authMethod() default ""; /** * The transportGuarantee specifies that the communication * between client and server should be NONE, INTEGRAL, or * CONFIDENTIAL. NONE means that the application does not require any * transport guarantees. A value of INTEGRAL means that the application * requires that the data sent between the client and server be sent in * such a way that it can't be changed in transit. CONFIDENTIAL means * that the application requires that the data be transmitted in a * fashion that prevents other entities from observing the contents of * the transmission. In most cases, the presence of the INTEGRAL or * CONFIDENTIAL flag will indicate that the use of SSL is required. */ String transportGuarantee() default ""; /** * A secure endpoint does not by default publish it's wsdl on an unsecure transport. * You can override this behaviour by explicitly setting the secureWSDLAccess flag to false. * * Protect access to WSDL. See http://jira.jboss.org/jira/browse/JBWS-723 */ boolean secureWSDLAccess() default true; }
/** * Annotation for specifying the JBoss security domain for an EJB * * @author <a href="mailto:bill@jboss.org">Bill Burke</a> **/ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface SecurityDomain { /** * The required name for the security domain. * * Do not use the JNDI name * * Good: "MyDomain" * Bad: "java:/jaas/MyDomain" */ String value(); /** * The name for the unauthenticated pricipal */ String unauthenticatedPrincipal() default ""; }
As indicated in Chapter 1, Introduction the JBoss Application Server 5 is designed around the advanced concept of a Virtual Deployment Framework (VDF). This chapter discusses the JBoss5 Virtual Deployment Framework further. The following UML diagram illustrates an overview of the key JBoss5 Deployment Framework classes.
The key classes in the above diagram are:
isRelevant() : does the deployer want to process the unit.
prepareDeploy() : take the new deployment to the ready stage
prepareUndeploy() : get ready to undeploy
handoff(new, old) : handover control from new to old
commitDeploy() : new deployment is now in control
commitUndeploy() : old deployment is out of here
getRelativeOrder() : specify the relative order of the deployer in a chain
DeploymentUnit : a representation of a runtime unit of work a Deployer operates on.
DeploymentContext : a representation of structural aspects of deployable content.
ManagedObject : a representation of the manageable properties for a deployment.
VFS : the api for representing the read-only file system of the deployment.
VirtualFile : the api for a file in the deployment.
In addition, the implementation adds the following methods.
public synchronized void removeDeployer(Deployer deployer) : removes a component Deployer.
public synchronized Set <Deployer> getDeployers() : get the registered component deployers.
public synchronized void setDeployers(Set<Deployer> deployers) : set the component deployers.
org.jboss.deployers.plugins.structure.vfs.AbstractStructureDeployer
org.jboss.deployers.plugins.structure.vfs.file.FileStructure
org.jboss.deployers.plugins.structure.vfs.jar.JARStructure
org.jboss.deployers.plugins.structure.vfs.war.WARStructure
protected abstract T parse(DeploymentUnit unit, VirtualFile file) - abstract.
protected void init(DeploymentUnit unit, T metaData, VirtualFile file) - empty.
public abstract void deploy(DeploymentUnit unit, T deployment);
public abstract void undeploy(DeploymentUnit unit, T deployment);
org.jboss.deployers.plugins.deployers.kernel.BeanDeployer
org.jboss.deployers.plugins.deployers.kernel.KernelDeploymentDeployer
org.jboss.deployers.plugins.deployers.kernel.BeanMetaDataDeployer
org.jboss.system.deployers.SARDeployer
org.jboss.system.deployers.ServiceClassLoaderDeployer
org.jboss.system.deployers.ServiceDeploymentDeployer
org.jboss.system.deployers.ServiceDeployer
org.jboss.deployment.WebAppParsingDeployer
org.jboss.deployment.JBossWebAppParsingDeployer
org.jboss.web.tomcat.tc6.deployers.TomcatDeployer
JBoss AOP is a 100% Pure Java Aspected Oriented Framework usable in any programming environment or tightly integrated with our application server. Aspects allow you to more easily modularize your code base when regular object oriented programming just doesn't fit the bill. It can provide a cleaner separation from application logic and system code. It provides a great way to expose integration points into your software. Combined with JDK 1.5 Annotations, it also is a great way to expand the Java language in a clean pluggable way rather than using annotations solely for code generation.
JBoss AOP is not only a framework, but also a prepackaged set of aspects that are applied via annotations, pointcut expressions, or dynamically at runtime. Some of these include caching, asynchronous communication, transactions, security, remoting, and many many more.
An aspect is a common feature that's typically scattered across methods, classes, object hierarchies, or even entire object models. It is behavior that looks and smells like it should have structure, but you can't find a way to express this structure in code with traditional object-oriented techniques.
For example, metrics is one common aspect. To generate useful logs from your application, you have to (often liberally) sprinkle informative messages throughout your code. However, metrics is something that your class or object model really shouldn't be concerned about. After all, metrics is irrelevant to your actual application: it doesn't represent a customer or an account, and it doesn't realize a business rule. It's simply orthogonal.
public class BankAccountDAO { public void withdraw(double amount) { long startTime = System.currentTimeMillis(); try { // Actual method body... } finally { long endTime = System.currentTimeMillis() - startTime; System.out.println("withdraw took: " + endTime); } } }
While this code works, there are a few problems with this approach:
The following listing demonstrates Implementing metrics in a JBoss AOP Interceptor
01. public class Metrics implements org.jboss.aop.advice.Interceptor 02. { 03. public Object invoke(Invocation invocation) throws Throwable 04. { 05. long startTime = System.currentTimeMillis(); 06. try 07. { 08. return invocation.invokeNext(); 09. } 10. finally 11. { 12. long endTime = System.currentTimeMillis() - startTime; 13. java.lang.reflect.Method m = ((MethodInvocation)invocation).method; 14. System.out.println("method " + m.toString() + " time: " + endTime + "ms"); 15. } 16. } 17. }
The following listing demonstrates defining a pointcut in JBoss AOP
1. <bind pointcut="public void com.mc.BankAccountDAO->withdraw(double amount)"> 2. <interceptor class="com.mc.Metrics"/> 3. </bind > 4. <bind pointcut="* com.mc.billing.*->*(..)"> 5. <interceptor class="com.mc.Metrics"/> 6. </bind >]]></programlisting>
maintaining object references even after replication or persistence.
fine grained replication, where only modified object fields are replicated.
"API-less" clustering model where pojos are simply annotated as being clustered.
Pojo Cache deployment in the JBoss AS5 is discussed more in Section 8.5, “Pojo Cache Deployment Options”
replicated to some or all cache instances in a cluster.
persisted to disk and/or a remote cluster ("far-cache").
garbage collected from memory when memory runs low, and passivated to disk so state isn't lost.
In addition, JBoss Cache offers a rich set of enterprise-class features:
being able to participate in JTA transactions (works with Java EE compliant TransactionManagers).
attach to JMX servers and provide runtime statistics on the state of the cache.
allow client code to attach listeners and receive notifications on cache events.
JBoss Cache uses JGroups as a transport layer. More information on JGroups can be found on Chapter 10, JGroups
In the JBoss Application Server 5, JBoss cache runs in the all configuration of the application server(i.e <JBOSS_HOME>/server/all). All you need to do is start the server with this configuration.
<JBOSS_HOME>/bin/./run.sh -c all
All
required jars will be on the classpath. Otherwise, you will need to
ensure jbosscache.jar and jgroups-all.jar are on the classpath. You may
need to add other jars if you're using things like JdbmCacheLoader. The simplest way to do this is to copy the jars from the JBoss Cache distribution's lib directory to the server configurations
all
lib directory. You could also package the jars with the configuration file in Service Archive (.sar) file or an EAR.
It is possible to deploy a JBoss Cache 2.0 instance in JBoss AS 4.x (at least in 4.2.0.GA; other AS releases are completely untested). However, the significant API changes between the JBoss Cache 2.x and 1.x releases mean none of the standard AS 4.x clustering services (e.g. http session replication) that rely on JBoss Cache will work with JBoss Cache 2.x. Also, be aware that usage of JBoss Cache 2.x in AS 4.x is not something the JBoss Cache developers are making any significant effort to test, so be sure to test your application well (which of course you're doing anyway.)
Note in the http://labs.jboss.com/file-access/default/members/jbosscache/freezone/docs/2.1.0.GA/userguide_en/html_single/index.html#sample_xml_file the value of the mbean element's code attribute: org.jboss.cache.jmx.CacheJmxWrapper . This is the class JBoss Cache uses to handle JMX integration; the Cache itself does not expose an MBean interface. See the JBoss Cache MBeans section for more on the CacheJmxWrapper .
Once your cache is deployed, in order to use it with an in-VM client such as a servlet, a JMX proxy can be used to get a reference to the cache:
MBeanServer server = MBeanServerLocator.locateJBoss();
ObjectName on = new ObjectName("jboss.cache:service=Cache");
CacheJmxWrapperMBean cacheWrapper =
(CacheJmxWrapperMBean) MBeanServerInvocationHandler.newProxyInstance(server, on,
CacheJmxWrapperMBean.class, false);
Cache cache = cacheWrapper.getCache();
Node root = cache.getRoot(); // etc etc
The MBeanServerLocator class is a helper to find the (only) JBoss MBean server inside the current JVM. The javax.management.MBeanServerInvocationHandler class' newProxyInstance method creates a dynamic proxy implementing the given interface and uses JMX to dynamically dispatch methods invoked against the generated interface to the MBean. The name used to look up the MBean is the same as defined in the cache's configuration file.
Once the proxy to the CacheJmxWrapper is obtained, the getCache() will return a reference to the Cache itself.
There are a number of ways to deploy POJO Cache:
MBeanServer server = MBeanServerLocator.locateJBoss(); ObjectName on = new ObjectName("jboss.cache:service=PojoCache"); PojoCacheJmxWrapperMBean cacheWrapper = (PojoCacheJmxWrapperMBean) MBeanServerInvocationHandler.newProxyInstance(server, on, PojoCacheJmxWrapperMBean.class, false); PojoCache cache = cacheWrapper.getPojoCache();
<?xml version="1.0" encoding="UTF-8"?> <deployment xmlns="urn:jboss:bean-deployer:2.0"> <!-- First we create a Configuration object for the cache --> <bean name="ExampleCacheConfig" class="org.jboss.cache.config.Configuration"> ... details omitted </bean> <!-- The cache itself. --> <bean name="ExampleCache" class="org.jboss.cache.pojo.impl.PojoCacheImpl"> <constructor factoryClass="org.jboss.cache.pojo.PojoCacheFactory factoryMethod="createCache"> <parameter><inject bean="ExampleCacheConfig"/></parameter> <parameter>false</false> </constructor> </bean> </deployment>....
JBoss Transactions runs in the all server configurations or customized configurations based on the all configuration.
Transactions may be of a long duration, sometimes lasting hours, days, or more.
Participants may not allow their resources to be locked for long durations.
The communication infrastructure between participants may not be reliable.
Some of the ACID properties of traditional transactions are not mandatory.
A transaction may succeed even if only some of the participants choose to confirm and others cancel.
Transactions that have to be rolled back have the concept of compensation.
CORBA Object Transaction Service (OTS)
Java Enterprise (JEE) transactions
Web Services Coordination (WS-Coordination)
Web Services Atomic Transaction (WS-AtomicTransaction)
Web Services Business Activity Framework (WS-BusinessActivity)
JEE and CORBA transactioning features
Complete distributed transaction support
Automated failure recovery system
Flexible deployment: centralized and distributed transaction manager options
Interposition support for improved distributed transaction performance
Support for both checked and unchecked transaction behaviour
Support for CosTransaction::Current API
Direct and indirect transaction management
Synchronization interface support
Explicit and implicit transaction context propagation
Web services transactioning features
JBoss AS clustering is built on JGroups - a toolkit for reliable multicast communication between AS server nodes on an existing computer network. It can be used to create groups of processes whose members can send messages to each other. JGroups enables developers to create reliable multipoint (multicast) applications where reliability is a deployment issue. JGroups also relieves the application developer from implementing this logic themselves. This saves significant development time and allows for the application to be deployed in different environments without having to change code. The following are the key features of JGroup.
Group creation and deletion. Group members can be spread across LANs or WANs
Joining and leaving of groups
Membership detection and notification about joined/left/crashed members
Detection and removal of crashed members
Sending and receiving of member-to-group messages (point-to-multipoint)
Sending and receiving of member-to-member messages (point-to-point)
Transport protocols: UDP (IP Multicast), TCP, JMS
Fragmentation of large messages
Reliable unicast and multicast message transmission. Lost messages are retransmitted
Failure detection: crashed members are excluded from the membership
More information on JGroups can be found on the The JGroups homepage
The main objective of JBoss Remoting is to provide a single API for most network based invocations and related service that uses pluggable transports and data marshallers. The JBoss Remoting API provides the ability for making synchronous and asynchronous remote calls, push and pull callbacks, and automatic discovery of remoting servers. The intention is to allow for the addition of different transports to fit different needs, yet still maintain the same API for making the remote invocations and only requiring configuration changes, not code changes, to fit these different needs.
JBossRemoting is a standalone project but is included in the recent releases of the JBoss Application Server including AS5 and can be run as a service within the container as well. This chapter discusses the JBoss Remoting service configurations.
The features available with JBoss Remoting are:
Asynchronous calls – can make asynchronous, or one way, calls to server.
Clustering - seamless client failover for remote invocations.
Connection failure notification - notification if client or server has failed
All the features within JBoss Remoting were created with ease of use and extensibility in mind. If you have a suggestion for a new feature or an improvement to a current feature, please log in our issue tracking system at http://jira.jboss.com.
JBoss Messaging is the new enterprise messaging system from JBoss. It is a complete rewrite of JBossMQ, the legacy JBoss JMS provider. It is the default JMS provider on JBoss AS 5. Production support is already available through JBoss EAP 4.3, and we offer developer support for JBoss 4.2.x.
JBoss Messaging is a high Performance JMS 1.1 compliant implementation integrated with JBoss Transactions. It also offers:
Clustered Queues and Topics by Default
Intelligent Message Redistributions
Transparent Failover
In memory message Replication
JBoss Messaging will be the default JMS provider in later versions of JBoss Enterprise Application Platform, and JBoss Service Integration Platform. It is also the default JMS provider in JBoss Application Server 5, and is the default JMS provider for JBoss ESB.
JBoss Messaging is an integral part of Red Hat's strategy for messaging.
Compared with JBossMQ, JBoss Messaging offers improved performance in both single node and clustered environments.
JBoss Messaging also features a much better modular architecture that will allow us to add more features in the future.
JBoss Messaging provides an open source and standards-based messaging platform that brings enterprise-class messaging to the mass market. It also implements a high performance, robust messaging core that is designed to support the largest and most heavily utilized SOAs, enterprise service buses (ESBs) and other integration needs ranging from the simplest to the highest demand networks.
It allows you to smoothly distribute your application load across your cluster, intelligently balancing and utilizing each nodes CPU cycles, with no single point of failure, providing a highly scalable and performance clustering implementation.
JBoss Messaging includes a JMS front-end to deliver messaging in a standards-based format as well as being designed to be able to support other messaging protocols in the future.
JBoss Messaging is destined to become an integral part of the JBoss Enterprise Application Platform, and the new Service Integration Platform.
JBoss Messaging is also an integral part of Red Hat's strategy for messaging. JBoss Messaging is committed to AMQP ( AMQP)- the new messaging standard from Red Hat and others. Later versions of JBoss Messaging will support AMQP, and JBoss Messaging will be focussed on becoming the premier AMQP Java broker.
SecurityStore is a pluggable object, and it has a default implementation on messaging-service.xml.
<server> <mbean code="org.jboss.jms.server.security.SecurityMetadataStore" name="jboss.messaging:service=SecurityStore"> <attribute name="DefaultSecurityConfig"> <security> <role name="guest" read="true" write="true" create="true"/> </security> </attribute> <attribute name="SecurityDomain">java:/jaas/messaging</attribute> <attribute name="SuckerPassword">CHANGE ME!!</attribute> </mbean> ... ...file truncated..
The following are SecurityStore attributes from the messaging-service.xml file above.
<!-- ServerPeer MBean configuration ============================== --> <mbean code="org.jboss.jms.server.ServerPeer" name="jboss.messaging:service=ServerPeer" xmbean-dd="xmdesc/ServerPeer-xmbean.xml"> <!-- The unique id of the server peer - in a cluster each node MUST have a unique value - must be an integer --> <attribute name="ServerPeerID">${jboss.messaging.ServerPeerID:0}</attribute> <!-- The default JNDI context to use for queues when they are deployed without specifying one --> <attribute name="DefaultQueueJNDIContext">/queue</attribute> <!-- The default JNDI context to use for topics when they are deployed without specifying one --> <attribute name="DefaultTopicJNDIContext">/topic</attribute> <attribute name="PostOffice">jboss.messaging:service=PostOffice</attribute> <!-- The default Dead Letter Queue (DLQ) to use for destinations. This can be overridden on a per destinatin basis --> <attribute name="DefaultDLQ">jboss.messaging.destination:service=Queue,name=DLQ</attribute> <!-- The default maximum number of times to attempt delivery of a message before sending to the DLQ (if configured). This can be overridden on a per destinatin basis --> <attribute name="DefaultMaxDeliveryAttempts">10</attribute> <!-- The default Expiry Queue to use for destinations. This can be overridden on a per destinatin basis --> <attribute name="DefaultExpiryQueue">jboss.messaging.destination:service=Queue,name=ExpiryQueue</attribute> <!-- The default redelivery delay to impose. This can be overridden on a per destination basis --> <attribute name="DefaultRedeliveryDelay">0</attribute> <!-- The periodicity of the message counter manager enquiring on queues for statistics --> <attribute name="MessageCounterSamplePeriod">5000</attribute> <!-- The maximum amount of time for a client to wait for failover to start on the server side after it has detected failure --> <attribute name="FailoverStartTimeout">60000</attribute> <!-- The maximum amount of time for a client to wait for failover to complete on the server side after it has detected failure --> <attribute name="FailoverCompleteTimeout">300000</attribute> <attribute name="StrictTck">false</attribute> <!-- The maximum number of days results to maintain in the message counter history --> <attribute name="DefaultMessageCounterHistoryDayLimit">-1</attribute> <!-- The name of the connection factory to use for creating connections between nodes to pull messages --> <attribute name="ClusterPullConnectionFactoryName">jboss.messaging.connectionfactory:service=ClusterPullConnectionFactory</attribute> <!-- When redistributing messages in the cluster. Do we need to preserve the order of messages received by a particular consumer from a particular producer? --> <attribute name="DefaultPreserveOrdering">false</attribute> <!-- Max. time to hold previously delivered messages back waiting for clients to reconnect after failover --> <attribute name="RecoverDeliveriesTimeout">300000</attribute> <!-- The password used by the message sucker connections to create connections. THIS SHOULD ALWAYS BE CHANGED AT INSTALL TIME TO SECURE SYSTEM <attribute name="SuckerPassword"></attribute> --> <!-- The name of the server aspects configuration resource <attribute name="ServerAopConfig">aop/jboss-aop-messaging-server.xml</attribute> --> <!-- The name of the client aspects configuration resource <attribute name="ClientAopConfig">aop/jboss-aop-messaging-client.xml</attribute> --> <depends optional-attribute-name="PersistenceManager">jboss.messaging:service=PersistenceManager</depends> <depends optional-attribute-name="JMSUserManager">jboss.messaging:service=JMSUserManager</depends> <depends>jboss.messaging:service=Connector,transport=bisocket</depends> <depends optional-attribute-name="SecurityStore" proxy-type="org.jboss.jms.server.SecurityStore">jboss.messaging:service=SecurityStore</depends> </mbean> ...
This section discusses the MBean attributes of the ServerPeer MBean.
Periodically the server will query each queue to gets its statistics. This is the period.
The default value is 10000 milliseconds.
This operation lets you programmatically deploy a topic.
There are two overloaded versions of this operation.
If the topic already exists but is undeployed it is deployed. Otherwise it is created and deployed.
The name parameter represents the name of the destination to deploy.
This operation lets you programmatically destroy a topic.
The topic is undeployed and then all its data is destroyed from the database.
This operation returns true if the topic was successfully destroyed. otherwise it returns false.
IBM DB2 JDBC drivers can be downloaded from the IBM web site http://www-306.ibm.com/software/data/db2/java/.
Sybase JDBC drivers can be downloaded from the Sybase jConnect product page http://www.sybase.com/products/allproductsa-z/softwaredeveloperkit/jconnect
MS SQL Server JDBC drivers can be downloaded from the MSDN web site http://msdn.microsoft.com/data/jdbc/.
sp_dboption db_name, "allow nulls by default", true
Refer the sybase manuals for more options.
sp_configure "enable java",1
Refer to the sybase manuals for more information.
com.sybase.jdbc2.jdbc.SybSQLException: Cannot run this command because Java services are not enabled. A user with System Administrator (SA) role must reconfigure the system to enable Java
installjava -f <jar-file-name> -S<sybase-server> -U<super-user> -P<super-pass> -D<db-name>
Refer the installjava manual in Sybase for more options.
You have to be a super-user with required privileges to install java classes.
The jar file you are trying to install should be created without compression.
The schema for the top-level datasource elements of the *-ds.xml configuration deployment file is shown in Figure 13.1, “The simplified JCA DataSource configuration descriptor top-level schema elements”.
no-tx-datasource
: This element is used to specify the (org.jboss.resource.connectionmanager) NoTxConnectionManager service configuration. NoTxConnectionManager is a JCA connection manager with no transaction support. The no-tx-datasource child element schema is given in Figure 13.2, “The non-transactional DataSource configuration schema”.
local-tx-datasource
: This element is used to specify the (org.jboss.resource.connectionmanager) LocalTxConnectionManager service configuration. LocalTxConnectionManager implements a ConnectionEventListener that implements XAResource to manage transactions through the transaction manager. To ensure that all work in a local transaction occurs over the same ManagedConnection, it includes a xid to ManagedConnection map. When a Connection is requested or a transaction started with a connection handle in use, it checks to see if a ManagedConnection already exists enrolled in the global transaction and uses it if found. Otherwise, a free ManagedConnection has its LocalTransaction started and is used. The local-tx-datasource child element schema is given in Figure 13.3, “The non-XA DataSource configuration schema”
xa-datasource
: This element is used to specify the (org.jboss.resource.connectionmanager) XATxConnectionManager service configuration. XATxConnectionManager implements a ConnectionEventListener that obtains the XAResource to manage transactions through the transaction manager from the adaptor ManagedConnection. To ensure that all work in a local transaction occurs over the same ManagedConnection, it includes a xid to ManagedConnection map. When a Connection is requested or a transaction started with a connection handle in use, it checks to see if a ManagedConnection already exists enrolled in the global transaction and uses it if found. Otherwise, a free ManagedConnection has its LocalTransaction started and is used. The xa-datasource child element schema is given in Figure 13.4, “The XA DataSource configuration schema”.
ha-local-tx-datasource
: This element is identical to local-tx-datasource,
with the addition of the experimental datasource failover capability
allowing JBoss to failover to an alternate database in the event of a
database failure.
ha-xa-datasource
: This element is identical to xa-datasource,
with the addition of the experimental datasource failover capability
allowing JBoss to failover to an alternate database in the event of a
database failure.
Elements that are common to all datasources include:
org.jboss.resource.adapter.jdbc.vendor.OracleExceptionSorter
org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter
org.jboss.resource.adapter.jdbc.vendor.SybaseExceptionSorter
org.jboss.resource.adapter.jdbc.vendor.InformixExceptionSorte
Additional common child elements for both no-tx-datasource and local-tx-datasource include:
Elements in common to the local-tx-datasource and xa-datasource are:
The unique xa-datasource child elements are:
The failover options common to ha-xa-datasource and ha-local-tx-datasource are:
<datasources> <local-tx-datasource> <jndi-name>MySqlDS</jndi-name> <connection-url>jdbc:mysql://localhost:3306/jboss</connection-url> <driver-class>com.mysql.jdbc.Driver</driver-class> <user-name>jbossuser</user-name> <password>jbosspass</password> <exception-sorter-class-name> org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter </exception-sorter-class-name> <!-- should only be used on drivers after 3.22.1 with "ping" support <valid-connection-checker-class-name> org.jboss.resource.adapter.jdbc.vendor.MySQLValidConnectionChecker </valid-connection-checker-class-name> --> <!-- sql to call when connection is created <new-connection-sql>some arbitrary sql</new-connection-sql> --> <!-- sql to call on an existing pooled connection when it is obtained from pool - MySQLValidConnectionChecker is preferred for newer drivers <check-valid-connection-sql>some arbitrary sql</check-valid-connection-sql> --> <!-- corresponding type-mapping in the standardjbosscmp-jdbc.xml (optional) --> <metadata> <type-mapping>mySQL</type-mapping> </metadata> </local-tx-datasource> </datasources>
<mbean> - a standard jboss mbean deployment
<jndi-name> - the jndi name where it is bound. This is prefixed with java by default:
<use-java-context> - set this to false to drop the java: context from the jndi name
<xa-resource-timeout> - the number of seconds passed to
XAResource.setTranasctionTimeout()
when not zero. This feature is available on JBoss AS 4.0.3 and above.
JCA Login Modules - are used to inject security configuration into the connection when configured
<min-pool-size> - the minimum number of connections in the pool (default 0 - zero)
<max-pool-size> - the maximum number of connections in the pool (default 20)
MySQL: mysql-jdbc2-service.xml
PostgreSQL: postgres-jdbc2-service.xml
Oracle: oracle-jdbc2-service.xml
Sybase: sybase-jdbc2-service.xml
MS SQL Server: mssql-jdbc2-service.xml
Oracle 9i: org.hibernate.dialect.Oracle9iDialect
Oracle 10g: org.hibernate.dialect.Oracle10gDialect
Microsoft SQL Server 2005: org.hibernate.dialect.SQLServerDialect
PostgresSQL 8.1: org.hibernate.dialect.PostgreSQLDialect
MySQL 5.0: org.hibernate.dialect.MySQL5Dialect
DB2 8.0: org.hibernate.dialect.DB2Dialect
Sybase ASE 12.5: org.hibernate.dialect.SybaseDialect
All JBoss services work with the JDBC Type 2 driver and DB2 Version 7.2 servers.
.. ... <mbean code="org.jboss.mq.pm.jdbc2.PersistenceManager" name="jboss.mq:service=PersistenceManager"%gt; <depends optional-attribute-name="ConnectionManager"> jboss.jca:service=DataSourceBinding,name=DefaultDS </depends> ... ...
<mbean code="org.jboss.ejb.txtimer.DatabasePersistencePolicy" name="jboss.ejb:service=EJBTimerService,persistencePolicy=database"> <!-- DataSourceBinding ObjectName --> <depends optional-attribute-name="DataSource"> jboss.jca:service=DataSourceBinding,name=DefaultDS </depends> <!-- The plugin that handles database persistence --> <attribute name="DatabasePersistencePlugin"> org.jboss.ejb.txtimer.GeneralPurposeDatabasePersistencePlugin </attribute> <!-- The timers table name --> <attribute name="TimersTable">TIMERS</attribute> </mbean>
<!-- HiLoKeyGeneratorFactory --> <mbean code="org.jboss.ejb.plugins.keygenerator.hilo.HiLoKeyGeneratorFactory" name="jboss:service=KeyGeneratorFactory,type=HiLo"> <depends>jboss:service=TransactionManager</depends> <!-- Attributes common to HiLo factory instances --> <!-- DataSource JNDI name --> <depends optional-attribute-name="DataSource">jboss.jca:service=DataSourceBinding,name=DefaultDS</depends> <!-- table name --> <attribute name="TableName">HILOSEQUENCES</attribute>
DataSources are defined inside a <datasources> element.
<local-tx-datasource> - a DataSource that does not support two phase commit using a java.sql.Driver
<xa-datasource> - a DataSource that does support two phase commit using a javax.sql.XADataSource
<connection-url> - the JDBC driver connection url string
<driver-class> - the JDBC driver class implementing java.sql.Driver
<connection-property name="char.encoding">UTF-8</connection-property>
<xa-datasource-class> - the class implementing the XADataSource
<xa-datasource-property> - properties used to configure the XADataSource. For example:
<xa-datasource-property name="IfxWAITTIME">10</xa-datasource-property> <xa-datasource-property name="IfxIFXHOST">myhost.mydomain.com</xa-datasource-property> <xa-datasource-property name="PortNumber">1557</xa-datasource-property> <xa-datasource-property name="DatabaseName">mydb</xa-datasource-property> <xa-datasource-property name="ServerName">myserver</xa-datasource-property>
<jndi-name> - the JNDI name under which the DataSource should be bound.
<user-name> - the user name used when creating the connection (not used when security is configured)
<password> - the password used when creating the connection (not used when security is configured)
<url-delimiter> - From JBoss5 database failover is part of the main datasource config
<url-property> - From JBoss5 database failover is part of the main datasource config
From JBoss AS 3.2.6 and above, track-statements has a new option:
<track-statements>nowarn</track-statements
This option closes Statements and ResultSets without a warning. It is also the new default value.
Connection c = dataSource.getConnection(); // auto-commit == false PreparedStatement ps1 = c.prepareStatement(...); ResultSet rs1 = ps1.executeQuery(); PreparedStatement ps2 = c.prepareStatement(...); ResultSet rs2 = ps2.executeQuery();
<datasources> <local-tx-datasource> <jndi-name>GenericDS</jndi-name> <connection-url>[jdbc: url for use with Driver class]</connection-url> <driver-class>[fully qualified class name of java.sql.Driver implementation]</driver-class> <user-name>x</user-name> <password>y</password> <!-- you can include connection properties that will get passed in the DriverManager.getConnection(props) call--> <!-- look at your Driver docs to see what these might be --> <connection-property name="char.encoding">UTF-8</connection-property> <transaction-isolation>TRANSACTION_SERIALIZABLE</transaction-isolation> <!--pooling parameters--> <min-pool-size>5</min-pool-size> <max-pool-size>100</max-pool-size> <blocking-timeout-millis>5000</blocking-timeout-millis> <idle-timeout-minutes>15</idle-timeout-minutes> <!-- sql to call when connection is created <new-connection-sql>some arbitrary sql</new-connection-sql> --> <!-- sql to call on an existing pooled connection when it is obtained from pool <check-valid-connection-sql>some arbitrary sql</check-valid-connection-sql> --> <set-tx-query-timeout/> <query-timeout>300</query-timeout> <!-- maximum of 5 minutes for queries --> <!-- pooling criteria. USE AT MOST ONE--> <!-- If you don't use JAAS login modules or explicit login getConnection(usr,pw) but rely on user/pw specified above, don't specify anything here --> <!-- If you supply the usr/pw from a JAAS login module --> <security-domain>MyRealm</security-domain> <!-- if your app supplies the usr/pw explicitly getConnection(usr, pw) --> <application-managed-security/> <!--Anonymous depends elements are copied verbatim into the ConnectionManager mbean config--> <depends>myapp.service:service=DoSomethingService</depends> </local-tx-datasource> <!-- you can include regular mbean configurations like this one --> <mbean code="org.jboss.tm.XidFactory" name="jboss:service=XidFactory"> <attribute name="Pad">true</attribute> </mbean> <!-- Here's an xa example --> <xa-datasource> <jndi-name>GenericXADS</jndi-name> <xa-datasource-class>[fully qualified name of class implementing javax.sql.XADataSource goes here]</xa-datasource-class> <xa-datasource-property name="SomeProperty">SomePropertyValue</xa-datasource-property> <xa-datasource-property name="SomeOtherProperty">SomeOtherValue</xa-datasource-property> <user-name>x</user-name> <password>y</password> <transaction-isolation>TRANSACTION_SERIALIZABLE</transaction-isolation> <!--pooling parameters--> <min-pool-size>5</min-pool-size> <max-pool-size>100</max-pool-size> <blocking-timeout-millis>5000</blocking-timeout-millis> <idle-timeout-minutes>15</idle-timeout-minutes> <!-- sql to call when connection is created <new-connection-sql>some arbitrary sql</new-connection-sql> --> <!-- sql to call on an existing pooled connection when it is obtained from pool <check-valid-connection-sql>some arbitrary sql</check-valid-connection-sql> --> <!-- pooling criteria. USE AT MOST ONE--> <!-- If you don't use JAAS login modules or explicit login getConnection(usr,pw) but rely on user/pw specified above, don't specify anything here --> <!-- If you supply the usr/pw from a JAAS login module --> <security-domain/> <!-- if your app supplies the usr/pw explicitly getConnection(usr, pw) --> <application-managed-security/> </xa-datasource> </datasources>
<datasources> <local-tx-datasource> <jndi-name>GenericDS</jndi-name> <use-java-context>false</use-java-context> <connection-url>...</connection-url>
Add the security-domain parameter to the *-ds.xml file.
<datasources> <local-tx-datasource> ... <security-domain>MyDomain</security-domain> ... </local-tx-datasource> </datasources>
<application-policy name="MyDomain"> <authentication> <login-module code="org.jboss.resource.security.SecureIdentityLoginModule" flag="required"> <module-option name="username">scott</module-option> <module-option name="password">-170dd0fbd8c13748</module-option> <module-option name="managedConnectionFactoryName">jboss.jca:service=LocalTxCM,name=OracleDSJAAS</module-option> </login-module> </authentication> </application-policy>
<login-module code="org.jboss.security.auth.spi.UsersRolesLoginModule" flag="required"> <module-option name="unauthenticatedIdentity">nobody</module-option> <module-option name="usersProperties">props/users.properties</module-option> <module-option name="rolesProperties">props/roles.properties</module-option> </login-module>
JBossJCA uses a ManagedConnectionPool to perform the pooling. The ManagedConnectionPool is made up of subpools depending upon the strategy chosen and other pooling parameters.
|
xml |
mbean |
Internal Name |
Description |
|
|
|
ByNothing |
OnePool |
A single pool of equivalent connections |
|
|
<application-managed-security/> |
ByApplication |
PoolByCRI |
Use the connection properties from allocateConnection() |
|
|
<security-domain/> |
ByContainer |
PoolBySubject |
A pool per Subject, e.g. preconfigured or EJB/Web login subjects |
|
|
<security-domain-and-applicaton/> |
ByContainerAndApplicaton |
PoolBySubjectAndCri |
A per Subject and connection property combination |
|
The xml names imply this is just about security. This is misleading.
For <security-domain-and-application/> the Subject always overrides any user/password from createConnection(user, password) in the CRI:
( ConnectionRequestInfo )
The pool is designed for concurrent usage.
Once this limit is reached, threads wait for the <blocking-timeout-seconds/> to use the pool before throwing a No Managed Connections Available
The number of connections in the pool is controlled by the pool sizes.
<min-pool-size/> - When the number of connections falls below this size, new connections are created
<max-pool-size/> - No more than this number of connections are created
The simplest format is to just run a "quick" sql statement:
<check-valid-connection-sql>select 1 from dual</check-valid-connection-sql>
<valid-connection-checker-class-name/>
<exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.OracleExceptionSorter</exception-sorter-class-name>
FATAL
errors the connection will be closed.
You have pad=true for the XidFactory? in conf/jboss-service.xml.
You have <isSameRM-override-value>false</isSameRM-override-value> in your oracle-xa-ds.xml.
You have <no-tx-separate-pools/> in your oracle-xa-ds.xml.
That your jbosscmp-jdbc.xml is specifying the same version of oracle as the one you use.
That the oracle server you connect to has XA.
A slightly more detailed set of instructions can be found at Configuring and using XA distributed transactions in WebSphere Studio - Oracle Exception section.
On the same network, even for the same service, we may have different clusters. Figure 16.1, “Clusters and server nodes” shows an example network of JBoss server instances divided into three clusters, with the third cluster only having one node. This sort of topology can be set up simply by configuring the AS instances such that within a set of nodes meant to form a cluster the Channel configurations and names match while they differ from any other channels on the same network.
<mbean code="org.jboss.ha.framework.server.ClusterPartition" name="jboss:service=DefaultPartition"> <! -- Name of the partition being built --> <attribute name="PartitionName"> ${jboss.partition.name:DefaultPartition} </attribute> <! -- The address used to determine the node name --> <attribute name="NodeAddress">${jboss.bind.address}</attribute> <! -- Determine if deadlock detection is enabled --> <attribute name="DeadlockDetection">False</attribute> <! -- Max time (in ms) to wait for state transfer to complete. Increase for large states --> <attribute name="StateTransferTimeout">30000</attribute> <! -- The JGroups protocol configuration --> <attribute name="PartitionConfig"> ... ... </attribute> </mbean>
Here, we omitted the detailed JGroups protocol configuration for this channel. JGroups handles the
underlying peer-to-peer communication between nodes, and its configuration is discussed in Section 22.1, “JGroups Configuration”. The following list shows the available configuration attributes
in the HAPartition MBean.
PartitionName
is an optional attribute to specify the
name of the cluster. Its default value is DefaultPartition. Use the -g (a.k.a. --partition) command line switch to set this value at JBoss startup.
NodeAddress is an optional attribute used to help generate a unique name for this node.
DeadlockDetection
is an optional boolean attribute that
tells JGroups to run message deadlock detection algorithms with every request. Its default
value is false.
StateTransferTimeout
is an optional attribute to specify the timeout for state replication
across the cluster (in milliseconds). State replication refers to the
process of obtaining initial application state from other
already-running cluster members at service startup. Its default value
is 30000.
PartitionConfig is an element to specify JGroup configuration options for this cluster (see Section 22.1, “JGroups Configuration”).
In order for nodes to form a cluster, they must have the exact same PartitionName and the ParitionConfig elements. Changes in either element on some but not all nodes would cause the cluster to split.
You can view the current cluster information by pointing your browser to the JMX console of any
JBoss instance in the cluster (i.e., http://hostname:8080/jmx-console/) and then
clicking on the jboss:service=DefaultPartition
MBean (change the MBean name to reflect your partitionr name if you use
the -g startup switch). A list of IP addresses for the current cluster
members is shown in the CurrentView field.
While it is technically possible to put a JBoss server instance into multiple HAPartitions at the same time, this practice is generally not recommended, as it increases management complexity.
The stub interceptors maintain up-to-date knowledge about the cluster. For instance, they know the IP addresses of all available server nodes, the algorithm to distribute load across nodes (see next section), and how to failover the request if the target node not available. As part of handling each service request, if the cluster topology has changed the server node updates the stub interceptor with the latest changes in the cluster. For instance, if a node drops out of the cluster, each of client stub interceptor is updated with the new configuration the next time it connects to any active node in the cluster. All the manipulations done by the service stub are transparent to the client application. The client-side interceptor clustering architecture is illustrated in Figure 16.2, “The client-side interceptor (proxy) architecture for clustering”.
Section 18.1, “Stateless Session Bean in EJB 2.x” describes how to enable the client proxy to handle the entire cluster restart.
Other JBoss services, in particular the HTTP-based services, do not require the client to download anything. The client (e.g., a web browser) sends in requests and receives responses directly over the wire according to certain communication protocols (e.g., the HTTP protocol). In this case, an external load balancer is required to process all requests and dispatch them to server nodes in the cluster. The client only needs to know about how to contact the load balancer; it has no knowledge of the JBoss AS instances behind the load balancer. The load balancer is logically part of the cluster, but we refer to it as “external” because it is not running in the same process as either the client or any of the JBoss AS instances. It can be implemented either in software or hardware. There are many vendors of hardware load balancers; the mod_jk Apache module is an excellent example of a software load balancer. An external load balancer implements its own mechanism for understanding the cluster configuration and provides its own load balancing and failover policies. The external load balancer clustering architecture is illustrated in Figure 16.3, “The external load balancer architecture for clustering”.
<?xml version="1.0" encoding="UTF-8"?> <server> <mbean code="org.jboss.ha.framework.server.FarmMemberService" name="jboss:service=FarmMember,partition=DefaultPartition"> ... <depends optional-attribute-name="ClusterPartition" proxy-type="attribute"> jboss:service=${jboss.partition.name:DefaultPartition} </depends> <attribute name="ScanPeriod">5000</attribute> <attribute name="URLs">farm/</attribute> ... </mbean> </server>
JNDI is one of the most important services provided by the application server. The JBoss HA-JNDI (High Availability JNDI) service brings the following features to JNDI:
Transparent failover of naming operations. If an HA-JNDI naming Context is connected to the HA-JNDI service on a particular JBoss AS instance, and that service fails or is shut down, the HA-JNDI client can transparently fail over to another AS instance.
Load balancing of naming operations. An HA-JNDI naming Context will automatically load balance its requests across all the HA-JNDI servers in the cluster.
Automatic client discovery of HA-JNDI servers (using multicast).
Unified view of JNDI trees cluster-wide. Client can connect to the HA-JNDI service running on any node in the cluster and find objects bound in JNDI on any other node. This is accomplished via two mechanisms:
Cross-cluster lookups. A client can perform a lookup and the server side HA-JNDI service has the ability to find things bound in regular JNDI on any node in the cluster.
A replicated cluster-wide context tree. An object bound into the HA-JNDI service will be replicated around the cluster, and a copy of that object will be available in-VM on each node in the cluster.
JNDI is a key component for many other interceptor-based clustering services: those services register themselves with the JNDI so that the client can lookup their proxies and make use of their services. HA-JNDI completes the picture by ensuring that clients have a highly-available means to look up those proxies. However, it is important to understand that using HA-JNDI (or not) has no effect whatsoever on the clustering behavior of the objects that are looked up. To illustrate:
If an EJB is not configured as clustered, looking up the EJB via HA-JNDI does not somehow result in the addition of clustering capabilities (load balancing of EJB calls, transparent failover, state replication) to the EJB.
If an EJB is configured as clustered, looking up the EJB via regular JNDI instead of HA-JNDI does not somehow result in the removal of the bean proxy's clustering capabilities.
If the binding is available in the cluster-wide JNDI tree, return it.
If no local JNDI service owns such a binding, a NameNotFoundException is finally raised.
Properties p = new Properties(); p.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory"); p.put(Context.URL_PKG_PREFIXES, "jboss.naming:org.jnp.interfaces"); p.put(Context.PROVIDER_URL, "localhost:1100"); // HA-JNDI port. return new InitialContext(p);
Properties p = new Properties(); p.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory"); p.put(Context.URL_PKG_PREFIXES, "jboss.naming:org.jnp.interfaces"); p.put("jnp.partitionName", "DefaultPartition"); // partition name. return new InitialContext(p);
<!-- Bind address of bootstrap and HA-JNDI RMI endpoints --> <attribute name="BindAddress">${jboss.bind.address}</attribute>
The bootstrap and HA-JNDI RMI endpoints are now defined separately:
<!-- Bind address of bootstrap endpoint --> <attribute name="BindAddress">${jboss.bind.address}</attribute> <!-- Bind address of the HA-JNDI RMI endpoint --> <attribute name="RmiBindAddress">${jboss.bind.address}</attribute>
<resource-ref> <res-ref-name>jms/ConnectionFactory</res-ref-name> <res-type>javax.jms.QueueConnectionFactory</res-type> <res-auth>Container</res-auth> </resource-ref> <resource-ref> <res-ref-name>jms/Queue</res-ref-name> <res-type>javax.jms.Queue</res-type> <res-auth>Container</res-auth> </resource-ref>
<resource-ref> <res-ref-name>jms/ConnectionFactory</res-ref-name> <jndi-name>jnp://localhost:1100/ConnectionFactory</jndi-name> </resource-ref> <resource-ref> <res-ref-name>jms/Queue</res-ref-name> <jndi-name>jnp://localhost:1100/queue/A</jndi-name> </resource-ref>
Go into the the jmx-console and execute the list operation on the jboss:service=JNDIView
mbean. Towards the bottom of the results, the contents of the "HA-JNDI
Namespace" are listed. Typically this will be empty; if any of your own
deployments are shown there and you didn't explicitly bind them there,
there's probably an improper jndi.properties file on the classpath.
Please visit the following link for an example: Problem with removing a Node from Cluster
The JNDI
client needs to be aware of the HA-JNDI cluster. You can pass a list of
JNDI servers (i.e., the nodes in the HA-JNDI cluster) to the java.naming.provider.url JNDI setting in the jndi.properties file. Each server node is identified by its IP address and the JNDI port number. The server nodes are separated by commas (see Section 17.2.3, “JBoss configuration” for how to configure the servers and ports).
java.naming.provier.url=server1:1100,server2:1100,server3:1100,server4:1100
When initialising, the JNP client code will try to get in touch with each server node from the list, one after the other, stopping as soon as one server has been reached. It will then download the HA-JNDI stub from this node.
There is no load balancing behavior in the JNP client lookup process itself. It just goes through the provider lists and uses the first available server to obtain the stub. The HA-JNDI provider list only needs to contain a subset of HA-JNDI nodes in the cluster.
The downloaded smart proxy contains the list of currently running nodes and the logic to load balance naming requests and to fail-over to another node if necessary. Furthermore, each time a JNDI invocation is made to the server, the list of targets in the proxy interceptor is updated (only if the list has changed since the last call).
If the property string java.naming.provider.url is empty or if all servers it mentions are not reachable, the JNP client will try to discover a HA-JNDI server through a multicast call on the network (auto-discovery). See the section called “JBoss configuration” on how to configure auto-discovery on the JNDI server nodes. Through auto-discovery, the client might be able to get a valid HA-JNDI server node without any configuration. Of course, for auto-discovery to work, the network segment(s) between the client and the server cluster must be configured to propagate such multicast datagrams.
By default the auto-discovery feature uses multicast group address 230.0.0.4 and port1102.
In addition to the java.naming.provider.url
property, you can specify a set of other properties. The following list
shows all clustering-related client side properties you can specify
when creating a new InitialContext. (All of the standard,
non-clustering-related environment properties used with regular JNDI
are also available.)
java.naming.provider.url: Provides a list of IP addresses and port
numbers for HA-JNDI provider nodes in the cluster. The client tries those providers one by
one and uses the first one that responds.
jnp.disableDiscovery: When set to true, this
property disables the automatic discovery feature. Default is
false.
jnp.partitionName:
In an environment where multiple HA-JNDI services bound to distinct
clusters (a.k.a. partitions), are running, this property allows you to
ensure that your client only accepts automatic-discovery responses from
servers in the desired partition. If you do not use the automatic
discovery feature (i.e. jnp.disableDiscovery is true), this property is
not used. By default, this property is not set and the automatic
discovery select the first HA-JNDI server that responds, irregardless
of the cluster partition name.
jnp.discoveryTimeout: Determines how much time the context will wait
for a response to its automatic discovery packet. Default is 5000 ms.
jnp.discoveryGroup:
Determines which multicast group address is used for the automatic
discovery. Default is 230.0.0.4. Must match the value of the
AutoDiscoveryAddress configured on the server side HA-JNDI service.
jnp.discoveryPort:
Determines which multicast group port is used for the automatic
discovery. Default is 1102. Must match the value of the
AutoDiscoveryPort configured on the server side HA-JNDI service.
jnp.discoveryTTL:
specifies the TTL (time-to-live) for autodiscovery IP multicast
packets. This value represents the number of network hops a multicast
packet can be allowed to propagate before networking equipment should
drop the packet. Despite its name, it does not represent a unit of
time.
<mbean code="org.jboss.ha.jndi.HANamingService" name="jboss:service=HAJNDI"> <depends optional-attribute-name="ClusterPartition" proxy-type="attribute">jboss:service=${jboss.partition.name:DefaultPartition}</depends> <mbean>
The full default configuration of the HANamingService MBean is as follows.
<mbean code="org.jboss.ha.jndi.HANamingService" name="jboss:service=HAJNDI"> <!-- We now inject the partition into the HAJNDI service instead of requiring that the partition name be passed --> <depends optional-attribute-name="ClusterPartition" proxy-type="attribute">jboss:service=${jboss.partition.name:DefaultPartition}</depends> <!-- Bind address of bootstrap and HA-JNDI RMI endpoints --> <attribute name="BindAddress">${jboss.bind.address}</attribute> <!-- Port on which the HA-JNDI stub is made available --> <attribute name="Port">1100</attribute> <!-- RmiPort to be used by the HA-JNDI service once bound. 0 => auto. --> <attribute name="RmiPort">1101</attribute> <!-- Accept backlog of the bootstrap socket --> <attribute name="Backlog">50</attribute> <!-- The thread pool service used to control the bootstrap and auto discovery lookups --> <depends optional-attribute-name="LookupPool" proxy-type="attribute">jboss.system:service=ThreadPool</depends> <!-- A flag to disable the auto discovery via multicast --> <attribute name="DiscoveryDisabled">false</attribute> <!-- Set the auto-discovery bootstrap multicast bind address. If not specified and a BindAddress is specified, the BindAddress will be used. --> <attribute name="AutoDiscoveryBindAddress">${jboss.bind.address}</attribute> <!-- Multicast Address and group port used for auto-discovery --> <attribute name="AutoDiscoveryAddress">${jboss.partition.udpGroup:230.0.0.4}</attribute> <attribute name="AutoDiscoveryGroup">1102</attribute> <!-- The TTL (time-to-live) for autodiscovery IP multicast packets --> <attribute name="AutoDiscoveryTTL">16</attribute> <!-- The load balancing policy for HA-JNDI --> <attribute name="LoadBalancePolicy">org.jboss.ha.framework.interfaces.RoundRobin</attribute> <!-- Client socket factory to be used for client-server RMI invocations during JNDI queries <attribute name="ClientSocketFactory">custom</attribute> --> <!-- Server socket factory to be used for client-server RMI invocations during JNDI queries <attribute name="ServerSocketFactory">custom</attribute> --> </mbean>
<mbean code="org.jboss.ha.jndi.HANamingService" name="jboss:service=HAJNDI"> <depends optional-attribute-name="ClusterPartition" proxy-type="attribute">jboss:service=MySpecialPartition</depends> <attribute name="Port">56789</attribute> </mbean>
Session EJBs provide remote invocation services. They are clustered based on the client-side
interceptor architecture. The client application for a clustered session bean is exactly the same as the
client for the non-clustered version of the session bean, except for a minor change to the
java.naming.provier.url system property to enable HA-JNDI lookup (see previous
section). No code change or re-compilation is needed on the client side. Now, let's check out how to
configure clustered session beans in EJB 2.x and EJB 3.0 server applications respectively.
<jboss> <enterprise-beans> <session> <ejb-name>nextgen.StatelessSession</ejb-name> <jndi-name>nextgen.StatelessSession</jndi-name> <clustered>True</clustered> <cluster-config> <partition-name>DefaultPartition</partition-name> <home-load-balance-policy> org.jboss.ha.framework.interfaces.RoundRobin </home-load-balance-policy> <bean-load-balance-policy> org.jboss.ha.framework.interfaces.RoundRobin </bean-load-balance-policy> </cluster-config> </session> </enterprise-beans> </jboss>
<jboss> <enterprise-beans> <session> <ejb-name>nextgen.StatefulSession</ejb-name> <jndi-name>nextgen.StatefulSession</jndi-name> <clustered>True</clustered> <cluster-config> <partition-name>DefaultPartition</partition-name> <home-load-balance-policy> org.jboss.ha.framework.interfaces.RoundRobin </home-load-balance-policy> <bean-load-balance-policy> org.jboss.ha.framework.interfaces.FirstAvailable </bean-load-balance-policy> <session-state-manager-jndi-name> /HASessionState/Default </session-state-manager-jndi-name> </cluster-config> </session> </enterprise-beans> </jboss>
The HASessionState service MBean is defined in the
all/deploy/cluster-service.xml file.
<mbean code="org.jboss.ha.hasessionstate.server.HASessionStateService" name="jboss:service=HASessionState"> <depends>jboss:service=Naming</depends> <!-- We now inject the partition into the HAJNDI service instead of requiring that the partition name be passed --> <depends optional-attribute-name="ClusterPartition" proxy-type="attribute"> jboss:service=${jboss.partition.name:DefaultPartition} </depends> <!-- JNDI name under which the service is bound --> <attribute name="JndiName">/HASessionState/Default</attribute> <!-- Max delay before cleaning unreclaimed state. Defaults to 30*60*1000 => 30 minutes --> <attribute name="BeanCleaningDelay">0</attribute> </mbean>
The configuration attributes in the HASessionState MBean are listed below.
<jboss> <session> <ejb-name>nextgen_RetryInterceptorStatelessSession</ejb-name> <invoker-bindings> <invoker> <invoker-proxy-binding-name> clustered-retry-stateless-rmi-invoker </invoker-proxy-binding-name> <jndi-name> nextgen_RetryInterceptorStatelessSession </jndi-name> </invoker> </invoker-bindings> <clustered>true</clustered> </session> <invoker-proxy-binding> <name>clustered-retry-stateless-rmi-invoker</name> <invoker-mbean>jboss:service=invoker,type=jrmpha</invoker-mbean> <proxy-factory>org.jboss.proxy.ejb.ProxyFactoryHA</proxy-factory> <proxy-factory-config> <client-interceptors> <home> <interceptor> org.jboss.proxy.ejb.HomeInterceptor </interceptor> <interceptor> org.jboss.proxy.SecurityInterceptor </interceptor> <interceptor> org.jboss.proxy.TransactionInterceptor </interceptor> <interceptor> org.jboss.proxy.ejb.RetryInterceptor </interceptor> <interceptor> org.jboss.invocation.InvokerInterceptor </interceptor> </home> <bean> <interceptor> org.jboss.proxy.ejb.StatelessSessionInterceptor </interceptor> <interceptor> org.jboss.proxy.SecurityInterceptor </interceptor> <interceptor> org.jboss.proxy.TransactionInterceptor </interceptor> <interceptor> org.jboss.proxy.ejb.RetryInterceptor </interceptor> <interceptor> org.jboss.invocation.InvokerInterceptor </interceptor> </bean> </client-interceptors> </proxy-factory-config> </invoker-proxy-binding>
public @interface Clustered { Class loadBalancePolicy() default LoadBalancePolicy.class; String partition() default "${jboss.partition.name:DefaultPartition}"; }
Here is an example of a clustered EJB 3.0 stateless session bean implementation.
@Stateless @Clustered public class MyBean implements MySessionInt { public void test() { // Do something cool } }
The @Clustered annotation can also be omitted and the clustering configuration applied in jboss.xml:
<jboss> <enterprise-beans> <session> <ejb-name>NonAnnotationStateful</ejb-name> <clustered>true</clustered> <cluster-config> <partition-name>FooPartition</partition-name> <load-balance-policy> org.jboss.ha.framework.interfaces.RandomRobin </load-balance-policy> </cluster-config> </session> </enterprise-beans> </jboss>
public @interface CacheConfig { String name() default "jboss.cache:service=EJB3SFSBClusteredCache"; int maxSize() default 10000; long idleTimeoutSeconds() default 300; boolean replicationIsPassivation() default true; long removalTimeoutSeconds() default 0; }
Here is an example of a clustered EJB 3.0 stateful session bean implementation.
@Stateful @Clustered @CacheConfig(maxSize=5000,removalTimeoutSeconds=18000) public class MyBean implements MySessionInt { private int state = 0; public void increment() { System.out.println("counter: " + (state++)); } }
public interface Optimized { boolean isModified(); }
<server> <mbean code="org.jboss..cache.TreeCache" name="jboss.cache:service=EJB3SFSBClusteredCache"> <attribute name="ClusterName"> ${jboss.partition.name:DefaultPartition}-SFSBCache </attribute> <attribute name="IsolationLevel">REPEATABLE_READ</attribute> <attribute name="CacheMode">REPL_ASYNC</attribute> <!-- We want to activate/inactivate regions as beans are deployed --> <attribute name="UseRegionBasedMarshalling">true</attribute> <!-- Must match the value of "useRegionBasedMarshalling" --> <attribute name="InactiveOnStartup">true</attribute> <attribute name="ClusterConfig"> ... ... </attribute> <!-- The max amount of time (in milliseconds) we wait until the initial state (ie. the contents of the cache) are retrieved from existing members. --> <attribute name="InitialStateRetrievalTimeout">17500</attribute> <!-- Number of milliseconds to wait until all responses for a synchronous call have been received. --> <attribute name="SyncReplTimeout">17500</attribute> <!-- Max number of milliseconds to wait for a lock acquisition --> <attribute name="LockAcquisitionTimeout">15000</attribute> <!-- Name of the eviction policy class. --> <attribute name="EvictionPolicyClass"> org.jboss.cache.eviction.LRUPolicy </attribute> <!-- Specific eviction policy configurations. This is LRU --> <attribute name="EvictionPolicyConfig"> <config> <attribute name="wakeUpIntervalSeconds">5</attribute> <name>statefulClustered</name> <!-- So default region would never timeout --> <region name="/_default_"> <attribute name="maxNodes">0</attribute> <attribute name="timeToIdleSeconds">0</attribute> </region> </config> </attribute> <!-- Store passivated sessions to the file system --> <attribute name="CacheLoaderConfiguration"> <config> <passivation>true</passivation> <shared>false</shared> <cacheloader> <class>org.jboss.cache.loader.FileCacheLoader</class> <!-- Passivate to the server data dir --> <properties> location=${jboss.server.data.dir}${/}sfsb </properties> <async>false</async> <fetchPersistentState>true</fetchPersistentState> <ignoreModifications>false</ignoreModifications> </cacheloader> </config> </attribute> </mbean> </server>
The configuration attributes in this MBean are essentially the same as the attributes in the standard JBoss Cache TreeCache MBean discussed
in Chapter 22, JBossCache and JGroups Services
. Again, we omitted the JGroups configurations in the
ClusterConfig attribute (see more in Section 22.1, “JGroups Configuration”). Two noteworthy items:
The cache is configured to support eviction. The EJB3 SFSB container uses the JBoss Cache eviction mechanism to manage SFSB passivation. When beans are deployed, the EJB container will programatically add eviction regions to the cache, one region per bean type.
A JBoss Cache CacheLoader is also configured; again to support SFSB passivation. When beans are evicted from the cache, the cache loader passivates them to a persistent store; in this case to the filesystem in the $JBOSS_HOME/server/all/data/sfsb directory. JBoss Cache supports a variety of different CacheLoader implementations that know how to store data to different persistent store types; see the JBoss Cache documentation for details. However, if you change the CacheLoaderConfiguration, be sure that you do not use a shared store (e.g., a single schema in a shared database.) Each node in the cluster must have its own persistent store, otherwise as nodes independently passivate and activate clustered beans, they will corrupt each others data.
In a JBoss AS cluster, the entity bean instance caches need to be kept in sync across all nodes. If an entity bean provides remote services, the service methods need to be load balanced as well.
To use a clustered entity bean, the application does not need to do anything special, except for looking up EJB 2.x remote bean references from the clustered HA-JNDI.
<jboss> <enterprise-beans> <entity> <ejb-name>nextgen.EnterpriseEntity</ejb-name> <jndi-name>nextgen.EnterpriseEntity</jndi-name> <clustered>True</clustered> <cluster-config> <partition-name>DefaultPartition</partition-name> <home-load-balance-policy> org.jboss.ha.framework.interfaces.RoundRobin </home-load-balance-policy> <bean-load-balance-policy> org.jboss.ha.framework.interfaces.FirstAvailable </bean-load-balance-policy> </cluster-config> </entity> </enterprise-beans> </jboss>
However, clustered EJB 2.x Entity Beans do not have a distributed locking mechanism or a
distributed cache. They can only be synchronized by using row-level locking at the database level
(see <row-lock> in the CMP specification) or by setting the Transaction
Isolation Level of your JDBC driver to be TRANSACTION_SERIALIZABLE. Because there
is no supported distributed locking mechanism or distributed cache Entity Beans use Commit Option
"B" by default (See standardjboss.xml and the container configurations Clustered
CMP 2.x EntityBean, Clustered CMP EntityBean, or Clustered BMP EntityBean). It is not recommended
that you use Commit Option "A" unless your Entity Bean is read-only. (There are some design patterns
that allow you to use Commit Option "A" with read-mostly beans. You can also take a look at the
Seppuku pattern http://dima.dhs.org/misc/readOnlyUpdates.html. JBoss may incorporate
this pattern into later versions.)
If you are using Bean Managed Persistence (BMP), you are going to have to implement synchronization on your own. The MVCSoft CMP 2.0 persistence engine (see http://www.jboss.org/jbossgroup/partners.jsp) provides different kinds of optimistic locking strategies that can work in a JBoss cluster.
<server> <mbean code="org.jboss.cache.TreeCache" name="jboss.cache:service=EJB3EntityTreeCache"> <depends>jboss:service=Naming</depends> <depends>jboss:service=TransactionManager</depends> <!-- Name of cluster. Needs to be the same on all nodes in the clusters, in order to find each other --> <attribute name="ClusterName"> ${jboss.partition.name:DefaultPartition}-EntityCache </attribute> <!-- Configure the TransactionManager --> <attribute name="TransactionManagerLookupClass"> org.jboss.cache.JBossTransactionManagerLookup </attribute> <attribute name="IsolationLevel">REPEATABLE_READ</attribute> <attribute name="CacheMode">REPL_SYNC</attribute> <!-- Must be true if any entity deployment uses a scoped classloader --> <attribute name="UseRegionBasedMarshalling">true</attribute> <!-- Must match the value of "useRegionBasedMarshalling" --> <attribute name="InactiveOnStartup">true</attribute> <attribute name="ClusterConfig"> ... ... </attribute> <attribute name="InitialStateRetrievalTimeout">17500</attribute> <attribute name="SyncReplTimeout">17500</attribute> <attribute name="LockAcquisitionTimeout">15000</attribute> <attribute name="EvictionPolicyClass"> org.jboss.cache.eviction.LRUPolicy </attribute> <!-- Specific eviction policy configurations. This is LRU --> <attribute name="EvictionPolicyConfig"> <config> <attribute name="wakeUpIntervalSeconds">5</attribute> <!-- Cache wide default --> <region name="/_default_"> <attribute name="maxNodes">5000</attribute> <attribute name="timeToLiveSeconds">1000</attribute> </region> </config> </attribute> </mbean> </server>
<!-- Clustered cache with TreeCache --> <property name="cache.provider_class"> org.jboss.ejb3.entity.TreeCacheProviderHook </property>
<property name="treecache.mbean.object_name"> jboss.cache:service=EJB3EntityTreeCache </property>
@Entity @Cache(usage=CacheConcurrencyStrategy.TRANSACTIONAL) public class Account implements Serializable { // ... ... }
<server> <mbean code="org.jboss.cache.TreeCache" name="jboss.cache:service=EJB3EntityTreeCache"> ... ... <attribute name="EvictionPolicyConfig"> <config> <attribute name="wakeUpIntervalSeconds">5</attribute> <region name="/_default_"> <attribute name="maxNodes">5000</attribute> <attribute name="timeToLiveSeconds">1000</attribute> </region> <!-- Separate eviction rules for Account entities --> <region name="/myprefix/com/mycompany/entities/Account"> <attribute name="maxNodes">10000</attribute> <attribute name="timeToLiveSeconds">5000</attribute> </region> ... ... </config> </attribute> </mbean> </server>
@Entity @Cache(usage=CacheConcurrencyStrategy.TRANSACTIONAL, region=”Account”) public class Account implements Serializable { // ... ... }
The eviction configuration would then become:
<server> <mbean code="org.jboss.cache.TreeCache" name="jboss.cache:service=EJB3EntityTreeCache"> ... ... <attribute name="EvictionPolicyConfig"> <config> <attribute name="wakeUpIntervalSeconds">5</attribute> <region name="/_default_"> <attribute name="maxNodes">5000</attribute> <attribute name="timeToLiveSeconds">1000</attribute> </region> <!-- Separate eviction rules for Account entities --> <region name="/myprefix/Account"> <attribute name="maxNodes">10000</attribute> <attribute name="timeToLiveSeconds">5000</attribute> </region> ... ... </config> </attribute> </mbean> </server>
First, in persistence.xml you need to tell Hibernate to enable query caching:
<property name="hibernate.cache.use_query_cache" value="true"/>
@Entity @Cache (usage=CacheConcurrencyStrategy.TRANSACTIONAL, region=”Account”) @NamedQueries({ @NamedQuery(name="account.bybranch", query="select acct from Account as acct where acct.branch = ?1", hints={@QueryHint(name="org.hibernate.cacheable",value="true")}) }) public class Account implements Serializable { // ... ... }
<server> <mbean code="org.jboss.cache.TreeCache" name="jboss.cache:service=EJB3EntityTreeCache"> ... ... <attribute name="EvictionPolicyConfig"> <config> <attribute name="wakeUpIntervalSeconds">5</attribute> <region name="/_default_"> <attribute name="maxNodes">5000</attribute> <attribute name="timeToLiveSeconds">1000</attribute> </region> <!-- Separate eviction rules for Account entities --> <region name="/myprefix/Account"> <attribute name="maxNodes">10000</attribute> <attribute name="timeToLiveSeconds">5000</attribute> </region> <!-- Cache queries for 10 minutes --> <region name="/myprefix/org/hibernate/cache/StandardQueryCache"> <attribute name="maxNodes">100</attribute> <attribute name="timeToLiveSeconds">600</attribute> </region> ... ... </config> </attribute> </mbean> </server>
@Entity @Cache (usage=CacheConcurrencyStrategy.TRANSACTIONAL, region=”Account”) @NamedQueries({ @NamedQuery(name="account.bybranch", query="select acct from Account as acct where acct.branch = ?1", hints={@QueryHint(name="org.hibernate.cacheable",value="true"), @QueryHint(name=”org.hibernate.cacheRegion,value=”Queries”) }) }) public class Account implements Serializable { // ... ... }
The related eviction configuration:
<server> <mbean code="org.jboss.cache.TreeCache" name="jboss.cache:service=EJB3EntityTreeCache"> ... ... <attribute name="EvictionPolicyConfig"> <config> <attribute name="wakeUpIntervalSeconds">5</attribute> <region name="/_default_"> <attribute name="maxNodes">5000</attribute> <attribute name="timeToLiveSeconds">1000</attribute> </region> <!-- Separate eviction rules for Account entities --> <region name="/myprefix/Account"> <attribute name="maxNodes">10000</attribute> <attribute name="timeToLiveSeconds">5000</attribute> </region> <!-- Cache queries for 10 minutes --> <region name="/myprefix/Queries"> <attribute name="maxNodes">100</attribute> <attribute name="timeToLiveSeconds">600</attribute> </region> ... ... </config> </attribute> </mbean> </server>
HTTP session replication is used to replicate the state associated with your web clients on other nodes of a cluster. Thus, in the event one of your node crashes, another node in the cluster will be able to recover. Two distinct functions must be performed:
Session state replication
Load-balancing of incoming invocations
State replication is directly handled by JBoss. When you run JBoss in the all
configuration, session state replication is enabled by default. Just
configure your web application as distributable in its web.xml (see below), deploy it, and its session state is automtically replicated across all JBoss instances in the cluster.
However, load-balancing is a different story; it is not handled by JBoss itself and requires an external load balancer. aThis function could be provided by specialized hardware switches or routers (Cisco LoadDirector for example) or by specialized software running on commodity hardware. As a very common scenario, we will demonstrate how to set up a software load balancer using Apache httpd and mod_jk.
A load-balancer tracks HTTP requests and, depending on the session to which the request is linked, it dispatches the request to the appropriate node. This is called load-balancing with sticky-sessions: once a session is created on a node, every future request will also be processed by that same node. Using a load-balancer that supports sticky-sessions but not configuring your web application for session replication allows you to scale very well by avoiding the cost of session state replication: each query will always be handled by the same node. But in case a node dies, the state of all client sessions hosted by this node (the shopping carts, for example) will be lost and the clients will most probably need to login on another node and restart with a new session. In many situations, it is acceptable not to replicate HTTP sessions because all critical state is stored in a database. In other situations, losing a client session is not acceptable and, in this case, session state replication is the price one has to pay.
Modify APACHE_HOME/conf/httpd.conf and add a single line at the end of the file:
# Include mod_jk's specific configuration file Include conf/mod-jk.conf
Next, create a new file named APACHE_HOME/conf/mod-jk.conf:
# Load mod_jk module # Specify the filename of the mod_jk lib LoadModule jk_module modules/mod_jk.so # Where to find workers.properties JkWorkersFile conf/workers.properties # Where to put jk logs JkLogFile logs/mod_jk.log # Set the jk log level [debug/error/info] JkLogLevel info # Select the log format JkLogStampFormat "[%a %b %d %H:%M:%S %Y]" # JkOptions indicates to send SSK KEY SIZE JkOptions +ForwardKeySize +ForwardURICompat -ForwardDirectories # JkRequestLogFormat JkRequestLogFormat "%w %V %T" # Mount your applications JkMount /application/* loadbalancer # You can use external file for mount points. # It will be checked for updates each 60 seconds. # The format of the file is: /url=worker # /examples/*=loadbalancer JkMountFile conf/uriworkermap.properties # Add shared memory. # This directive is present with 1.2.10 and # later versions of mod_jk, and is needed for # for load balancing to work properly JkShmFile logs/jk.shm # Add jkstatus for managing runtime data <Location /jkstatus/> JkMount status Order deny,allow Deny from all Allow from 127.0.0.1 </Location>
Please note that two settings are very important:
# Simple worker configuration file # Mount the Servlet context to the ajp13 worker /jmx-console=loadbalancer /jmx-console/*=loadbalancer /web-console=loadbalancer /web-console/*=loadbalancer
This will configure mod_jk to forward requests to /jmx-console and
/web-console to Tomcat.
# Define list of workers that will be used # for mapping requests worker.list=loadbalancer,status # Define Node1 # modify the host as your host IP or DNS name. worker.node1.port=8009 worker.node1.host=node1.mydomain.com worker.node1.type=ajp13 worker.node1.lbfactor=1 worker.node1.cachesize=10 # Define Node2 # modify the host as your host IP or DNS name. worker.node2.port=8009 worker.node2.host= node2.mydomain.com worker.node2.type=ajp13 worker.node2.lbfactor=1 worker.node2.cachesize=10 # Load-balancing behaviour worker.loadbalancer.type=lb worker.loadbalancer.balance_workers=node1,node2 worker.loadbalancer.sticky_session=1 #worker.list=loadbalancer # Status worker for managing load balancer worker.status.type=status
<Engine name="jboss.web" defaultHost="localhost" jvmRoute="node1"> ... ... </Engine>
<!-- Define an AJP 1.3 Connector on port 8009 --> <Connector port="8009" address="${jboss.bind.address}" protocol="AJP/1.3" emptySessionPath="true" enableLookups="false" redirectPort="8443" />
<attribute name="UseJK">true</attribute>
In Section 20.4, “Configure worker nodes in mod_jk”, we covered how to use sticky sessions to make sure that a client in a session always hits the same server node in order to maintain the session state. However, sticky sessions by themselves are not an ideal solution. If a node goes down, all its session data is lost. A better and more reliable solution is to replicate session data across the nodes in the cluster. This way, the client can hit any server node and obtain the same session state.
The jboss.cache:service=TomcatClusteringCache MBean makes use of JBoss Cache to
provide HTTP session replication services to the JBoss Tomcat cluster. This MBean is defined in the deploy/jboss-web-cluster.sar/META-INF/jboss-service.xml file.
Before AS 4.2.0, the location of the HTTP session cache configuration file was deploy/tc5-cluster.sar/META-INF/jboss-service.xml. Prior to AS 4.0.4 CR2, the file was named deploy/tc5-cluster-service.xml.
Below is a typical deploy/jbossweb-cluster.sar/META-INF/jboss-service.xml file. The
configuration attributes in the TomcatClusteringCache MBean are very similar to
those in the JBoss AS cache configuration.
<mbean code="org.jboss.cache.aop.TreeCacheAop"
name="jboss.cache:service=TomcatClusteringCache">
<depends>jboss:service=Naming</depends>
<depends>jboss:service=TransactionManager</depends>
<depends>jboss.aop:service=AspectDeployer</depends>
<attribute name="TransactionManagerLookupClass">
org.jboss.cache.BatchModeTransactionManagerLookup
</attribute>
<attribute name="IsolationLevel">REPEATABLE_READ</attribute>
<attribute name="CacheMode">REPL_ASYNC</attribute>
<attribute name="ClusterName">
Tomcat-${jboss.partition.name:Cluster}
</attribute>
<attribute name="UseMarshalling">false</attribute>
<attribute name="InactiveOnStartup">false</attribute>
<attribute name="ClusterConfig">
... ...
</attribute>
<attribute name="LockAcquisitionTimeout">15000</attribute>
<attribute name="SyncReplTimeout">20000</attribute>
</mbean>
Note
that the value of the mbean element's code attribute is
org.jboss.cache.aop.TreeCacheAop, which is different from the other
JBoss Cache Mbeans used in JBoss AS. This is because FIELD granularity
HTTP session replication (covered below) needs the added features of
the TreeCacheAop (a.k.a. PojoCache) class.
The details of all the configuration options for a TreeCache MBean are covered in the JBoss Cache documentation. Below, we will just discuss several attributes that are most relevant to the HTTP cluster session replication.
TransactionManagerLookupClass
sets the transaction
manager factory. The default value is
org.jboss.cache.BatchModeTransactionManagerLookup. It tells the cache
NOT to participate in JTA-specific transactions. Instead, the cache manages its own transactions. Please do not change this.
CacheMode
controls how the cache is replicated. The valid
values are REPL_SYNC and REPL_ASYNC.
With either setting the client request thread updates the local cache
with the current sesssion contents and then sends a message to the
caches on the other members of the cluster, telling them to make the
same change. With REPL_ASYNC (the default) the request thread returns
as soon as the update message has been put on the network. With
REPL_SYNC, the request thread blocks until it gets a reply message from
all cluster members, informing it that the update was successfully
applied. Using synchronous replication makes sure changes are applied
aroundthe cluster before the web request completes. However,
synchronous replication is much slower.
ClusterName specifies the name of the cluster that the cache works within. The default cluster name is the the word "Tomcat-" appended by the current JBoss partition name. All the nodes must use the same cluster name.
The
UseMarshalling
and
InactiveOnStartup
attributes must have the same value. They must be
true if FIELD level session replication is needed
(see later). Otherwise, they are default to false.
ClusterConfig configures the underlying JGroups stack. Please refer to Section 22.1, “JGroups Configuration” for more information.
LockAcquisitionTimeout sets the maximum number of milliseconds to wait for a lock acquisition when trying to lock a cache node. The default value is 15000.
SyncReplTimeout sets the maximum number of milliseconds to wait for a response from all nodes in the cluster when a synchronous replication message is sent out. The default value is 20000; should be a few seconds longer than LockAcquisitionTimeout.
<?xml version="1.0"?> <web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4"> <distributable/> <!-- ... --> </web-app>
<jboss-web> <replication-config> <replication-trigger>SET_AND_NON_PRIMITIVE_GET</replication-trigger> <replication-granularity>SESSION</replication-granularity> <replication-field-batch-mode>true</replication-field-batch-mode> </replication-config> </jboss-web>
@org.jboss.cache.aop.AopMarker public class Address { ... }
@org.jboss.cache.aop.InstanceOfAopMarker public class Person { ... } then when you have a sub-class like public class Student extends Person { ... }
/* * My usual comments here first. * @@org.jboss.web.tomcat.tc5.session.AopMarker */ public class Address { ... }
The anologue for @InstanceAopMarker is:
/* * * @@org.jboss.web.tomcat.tc5.session.InstanceOfAopMarker */ public class Person { ... }
$ annotationc [classpath] [source files or directories] $ javac -cp [classpath] [source files or directories] $ aopc [classpath] [class files or directories]
You can see a complete example on how to build, deploy, and validate a FIELD-level replicated web application from this page: http://wiki.jboss.org/wiki/Wiki.jsp?page=Http_session_field_level_example. The example bundles the pre- and post-compile tools so you do not need to download JBoss AOP separately.
When you deploy the web application into JBoss AS, make sure that the following configurations are correct:
In the server's deploy/jboss-web-cluster.sar/META-INF/jboss-service.xml file,
the inactiveOnStartup and useMarshalling attributes
must both be true.
In the application's jboss-web.xml file, the
replication-granularity attribute must be
FIELD.
Finally, let's see an example on how to use FIELD-level replication on those data classes. Notice
that there is no need to call session.setAttribute() after you make changes to
the data object, and all changes to the fields are automatically replicated across the cluster.
// Do this only once. So this can be in init(), e.g.
if(firstTime)
{
Person joe = new Person("Joe", 40);
Person mary = new Person("Mary", 30);
Address addr = new Address();
addr.setZip(94086);
joe.setAddress(addr);
mary.setAddress(addr); // joe and mary share the same address!
session.setAttribute("joe", joe); // that's it.
session.setAttribute("mary", mary); // that's it.
}
Person mary = (Person)session.getAttribute("mary");
mary.getAddress().setZip(95123); // this will update and replicate the zip code.
Besides plain objects, you can also use regular Java collections of those objects as session attributes. JBoss cache automatically figures out how to handle those collections and replicate field changes in their member objects.
/JSESSION /localhost /quote /FB04767C454BAB3B2E462A27CB571330 VERSION: 6 FB04767C454BAB3B2E462A27CB571330: org.jboss.invocation.MarshalledValue@1f13a81c /AxCI8Ovt5VQTfNyYy9Bomw** VERSION: 4 AxCI8Ovt5VQTfNyYy9Bomw**: org.jboss.invocation.MarshalledValue@e076e4c8
public class HASingletonExample implements HASingletonExampleMBean { private boolean isMasterNode = false; public void startSingleton() { isMasterNode = true; } . public boolean isMasterNode() { return isMasterNode; } public void stopSingleton() { isMasterNode = false; } }
<server> <!-- This MBean is an example of a clustered singleton --> <mbean code="org.jboss.ha.examples.HASingletonExample" name=“jboss:service=HASingletonExample"/> <!-- This HASingletonController manages the cluster Singleton --> <mbean code="org.jboss.ha.singleton.HASingletonController" name="jboss:service=ExampleHASingletonController"> <!-- Inject a ref to the HAPartition --> <depends optional-attribute-name="ClusterPartition" proxy-type="attribute"> jboss:service=${jboss.partition.name:DefaultPartition} </depends> <!-- Inject a ref to the service being controlled --> <depends optional-attribute-name="TargetName"> jboss:service=HASingletonExample </depends> <!-- Methods to invoke when become master / stop being master --> <attribute name="TargetStartMethod">startSingleton</attribute> <attribute name="TargetStopMethod">stopSingleton</attribute> </mbean> </server>
Voila! A clustered singleton service.
<mbean code="org.jboss.ha.singleton.HASingletonController" name="jboss.ha:service=HASingletonDeployer"> <depends optional-attribute-name="ClusterPartition" proxy-type="attribute"> jboss:service=${jboss.partition.name:DefaultPartition} </depends> <depends optional-attributeame="TargetName"> jboss.system:service=MainDeployer </depends> <attribute name="TargetStartMethod">deploy</attribute> <attribute name="TargetStartMethodArgument"> ${jboss.server.home.url}/deploy-hasingleton </attribute> <attribute name="TargetStopMethod">undeploy</attribute> <attribute name="TargetStopMethodArgument"> ${jboss.server.home.url}/deploy-hasingleton </attribute> </mbean>
JGroups and JBossCache provide the underlying communication, node replication and caching services, for JBoss AS clusters. Those services are configured as MBeans. There is a set of JBossCache and JGroups MBeans for each type of clustering applications (e.g., the Stateful Session EJBs, HTTP session replication etc.).
The JBoss AS ships with a reasonable set of default JGroups and JBossCache MBean configurations. Most applications just work out of the box with the default MBean configurations. You only need to tweak them when you are deploying an application that has special network or performance requirements.
The JGroups framework provides services to enable peer-to-peer communications between nodes in a cluster. It is built on top a stack of network communication protocols that provide transport, discovery, reliability and failure detection, and cluster membership management services. Figure 22.1, “Protocol stack in JGroups” shows the protocol stack in JGroups.
<mbean code="org.jboss.ha.framework.server.ClusterPartition" name="jboss:service=${jboss.partition.name:DefaultPartition}"> ... ... <attribute name="PartitionConfig"> <Config> <UDP mcast_addr="${jboss.partition.udpGroup:228.1.2.3}" mcast_port="${jboss.hapartition.mcast_port:45566}" tos="8" ucast_recv_buf_size="20000000" ucast_send_buf_size="640000" mcast_recv_buf_size="25000000" mcast_send_buf_size="640000" loopback="false" discard_incompatible_packets="true" enable_bundling="false" max_bundle_size="64000" max_bundle_timeout="30" use_incoming_packet_handler="true" use_outgoing_packet_handler="false" ip_ttl="${jgroups.udp.ip_ttl:2}" down_thread="false" up_thread="false"/> <PING timeout="2000" down_thread="false" up_thread="false" num_initial_members="3"/> <MERGE2 max_interval="100000" down_thread="false" up_thread="false" min_interval="20000"/> <FD_SOCK down_thread="false" up_thread="false"/> <FD timeout="10000" max_tries="5" down_thread="false" up_thread="false" shun="true"/> <VERIFY_SUSPECT timeout="1500" down_thread="false" up_thread="false"/> <pbcast.NAKACK max_xmit_size="60000" use_mcast_xmit="false" gc_lag="0" retransmit_timeout="300,600,1200,2400,4800" down_thread="false" up_thread="false" discard_delivered_msgs="true"/> <UNICAST timeout="300,600,1200,2400,3600" down_thread="false" up_thread="false"/> <pbcast.STABLE stability_delay="1000" desired_avg_gossip="50000" down_thread="false" up_thread="false" max_bytes="400000"/> <pbcast.GMS print_local_addr="true" join_timeout="3000" down_thread="false" up_thread="false" join_retry_timeout="2000" shun="true" view_bundling="true"/> <FRAG2 frag_size="60000" down_thread="false" up_thread="false"/> <pbcast.STATE_TRANSFER down_thread="false" up_thread="false" use_flush="false"/> </Config> </attribute> </mbean>
The following common properties are exposed by all of the JGroups protocols discussed below:
Generally speaking, up_thread and down_thread should be set to false.
<UDP mcast_addr="${jboss.partition.udpGroup:228.1.2.3}" mcast_port="${jboss.hapartition.mcast_port:45566}" tos="8" ucast_recv_buf_size="20000000" ucast_send_buf_size="640000" mcast_recv_buf_size="25000000" mcast_send_buf_size="640000" loopback="false" discard_incompatible_packets="true" enable_bundling="false" max_bundle_size="64000" max_bundle_timeout="30" use_incoming_packet_handler="true" use_outgoing_packet_handler="false" ip_ttl="${jgroups.udp.ip_ttl:2}" down_thread="false" up_thread="false"/>
The available attributes in the above JGroups configuration are listed below.
mcast_port
specifies the multicast port number. If omitted, the
default is 45566.
tos specifies traffic class for sending unicast and multicast datagrams.
<TCP start_port="7800" bind_addr="192.168.5.1" loopback="true" down_thread="false" up_thread="false"/>
Below are the attributes available in the TCP element.
<TUNNEL router_port="12001" router_host="192.168.5.1" down_thread="false" up_thread="false/>
The available attributes in the TUNNEL element are listed below.
router_host specifies the host on which the GossipRouter is running.
router_port specifies the port on which the GossipRouter is listening.
loopback
specifies whether to loop messages back up
the stack. The default is true.
The cluster needs to maintain a list of current member nodes at all times so that the load balancer and client interceptor know how to route their requests. Discovery protocols are used to discover active nodes in the cluster and detect the oldest member of the cluster, which is the coordinator. All initial nodes are discovered when the cluster starts up. When a new node joins the cluster later, it is only discovered after the group membership protocol (GMS, see Section 22.7.1, “Group Membership”) admits it into the group.
Since
the discovery protocols sit on top of the transport protocol, you can
choose to use different discovery protocols based on your transport
protocol. These are also configured as sub-elements in the JGroups
MBean Config element.
Here is an example PING configuration for IP multicast.
<PING timeout="2000" num_initial_members="2" down_thread="false" up_thread="false"/>
Here is another example PING configuration for contacting a Gossip Router.
<PING gossip_host="localhost" gossip_port="1234" timeout="3000" num_initial_members="3" down_thread="false" up_thread="false"/>
The available attributes in the PING element are listed below.
timeout specifies the maximum number of milliseconds to wait for any responses. The default is 3000.
gossip_host specifies the host on which the GossipRouter is running.
gossip_port specifies the port on which the GossipRouter is listening on.
<TCPGOSSIP timeout="2000" initial_hosts="192.168.5.1[12000],192.168.0.2[12000]" num_initial_members="3" down_thread="false" up_thread="false"/>
The available attributes in the TCPGOSSIP element are listed below.
timeout specifies the maximum number of milliseconds to wait for any responses. The default is 3000.
<TCPPING timeout="2000" initial_hosts="hosta[2300],hostb[3400],hostc[4500]" port_range="3" num_initial_members="3" down_thread="false" up_thread="false"/>
The available attributes in the TCPPING element are listed below.
timeout specifies the maximum number of milliseconds to wait for any responses. The default is 3000.
initial_hosts
is a comma-seperated list of addresses
(e.g., host1[12345],host2[23456]) for pinging.
<MPING timeout="2000" bind_to_all_interfaces="true" mcast_addr="228.8.8.8" mcast_port="7500" ip_ttl="8" num_initial_members="3" down_thread="false" up_thread="false"/>
The available attributes in the MPING element are listed below.
timeout specifies the maximum number of milliseconds to wait for any responses. The default is 3000.
bind_addr specifies the interface on which to send and receive multicast packets.
bind_to_all_interfaces
overrides the
bind_addr and uses all interfaces in multihome nodes.
<FD timeout="2000" max_tries="3" shun="true" down_thread="false" up_thread="false"/>
The available attributes in the FD element are listed below.
<FD_SOCK_down_thread="false" up_thread="false"/>
There available attributes in the FD_SOCK element are listed below.
<VERIFY_SUSPECT timeout="1500" down_thread="false" up_thread="false"/>
The available attributes in the FD_SOCK element are listed below.
An overloaded machine might be slow in sending are-you-alive responses.
A member will be suspected when suspended in a debugger/profiler.
Low timeouts lead to higher probability of false suspicions and higher network traffic.
High timeouts will not detect and remove crashed members for some time.
Suspended in a debugger is no problem because the TCP connection is still open.
High load no problem either for the same reason.
Members will only be suspected when TCP connection breaks
<FD_SOCK down_thread="false" up_thread="false"/> <FD timeout="10000" max_tries="5" shun="true" down_thread="false" up_thread="false" />
<UNICAST timeout="100,200,400,800" down_thread="false" up_thread="false"/>
There is only one configurable attribute in the UNICAST element.
<pbcast.NAKACK max_xmit_size="60000" use_mcast_xmit="false" retransmit_timeout="300,600,1200,2400,4800" gc_lag="0" discard_delivered_msgs="true" down_thread="false" up_thread="false"/>
The configurable attributes in the pbcast.NAKACK element are as follows.
<pbcast.GMS print_local_addr="true" join_timeout="3000" down_thread="false" up_thread="false" join_retry_timeout="2000" shun="true" view_bundling="true"/>
The configurable attributes in the pbcast.GMS element are as follows.
print_local_addr specifies whether to dump the node's own address to the output when started.
disable_initial_coord specifies whether to prevent this node as the cluster coordinator.
<FC max_credits="1000000" down_thread="false" up_thread="false" min_threshold="0.10"/>
The configurable attributes in the FC element are as follows.
<FRAG2 frag_size="60000" down_thread="false" up_thread="false"/>
The configurable attributes in the FRAG2 element are as follows.
<pbcast.STABLE stability_delay="1000" desired_avg_gossip="5000" down_thread="false" up_thread="false" max_bytes="400000"/>
The configurable attributes in the pbcast.STABLE element are as follows.
<MERGE2 max_interval="10000" min_interval="2000" down_thread="false" up_thread="false"/>
The configurable attributes in the FC element are as follows.
max_interval specifies the maximum number of milliseconds to send out a MERGE message.
min_interval specifies the minimum number of milliseconds to send out a MERGE message.
JGroups chooses a random value between min_interval and
max_interval to send out the MERGE message.
So, what are best practices for managing how JGroups binds to interfaces?
Binding JGroups to the same interface as other services. Simple, just use -b:
./run.sh -b 192.168.1.100 -c all
Binding services (e.g., JBoss Web) to one interface, but use a different one for JGroups:
./run.sh -b 10.0.0.100 -Djgroups.bind_addr=192.168.1.100 -c all
Binding services (e.g., JBoss Web) to all interfaces. This can be done like this:
./run.sh -b 0.0.0.0 -c all
Binding services (e.g., JBoss Web) to all interfaces, but specify the JGroups interface:
./run.sh -b 0.0.0.0 -Djgroups.bind_addr=192.168.1.100 -c all
Again, specifically setting the system property overrides the -b value.
Using different interfaces for different channels:
./run.sh -b 10.0.0.100 -Djgroups.ignore.bind_addr=true -c all
./run.sh -g QAPartition -b 192.168.1.100 -c all
<attribute name="ClusterName">Tomcat-${jboss.partition.name:Cluster}</attribute>
/run.sh -u 230.1.2.3 -g QAPartition -b 192.168.1.100 -c all
<Config> <UDP mcast_addr="${jboss.partition.udpGroup:228.1.2.3}" ....
/run.sh -u 230.1.2.3 -g QAPartition -Djboss.hapartition.mcast_port=12345 -Djboss.webpartition.mcast_port=23456 -Djboss.ejb3entitypartition.mcast_port=34567 -Djboss.ejb3sfsbpartition.mcast_port=45678 -b 192.168.1.100 -c all
Why isn't it sufficient to change the group name?
Why do I need to change the multicast port if I change the address?
java -cp jgroups.jar org.jgroups.tests.McastReceiverTest -mcast_addr 224.10.10.10 -port 5555
Then in another window start McastSenderTest:
java -cp jgroups.jar org.jgroups.tests.McastSenderTest -mcast_addr 224.10.10.10 -port 5555